DoubleAnimationとかでFrom, To, Durationなどを状況に応じて変更させるためにこれらにBindingを設定したいという状況は少なくないと思うのですが、ControlTemplate.TriggersやStyle.Triggers内で定義すると実行時に”Cannot freeze this Storyboard timeline tree for use across threads”なるメッセージの例外が出ます。
どうもはっきり理解できていないのですが、理由は以下のどちらかかな?- Animationやっている最中にFrom, To, Duration値が変えられると困る。なので少なくともStoryboard開始前にはこの値を固定(Freeze)する必要がある。値を動的に変えることが目的のBindingはこれに反する。
- TemplateやStyleは使いまわされることが前提なので、事前(多分Exe実行初期)にXamlをコンパイルしてパフォーマンスを改善している。よってコンパイル後値が変わる要因となるBindingは認められない。
ここの例 はStoryboardをリソース指定、開始をコードビハインドでやることで、うまく回避できているということでしょうか。Animation開始後にウィンドウサイズを変えてもボールの動きが追従しないので、Animation中は値が変えられないということがわかります。
コードビハインドで取得したリソースはDynamicResourceに相当する らしいので、Storyboardをリソースで指定してDynamicResourceで参照すればと試したのですが、少なくともControlTemplateではうまく行かず。
[参考]- "Cannot freeze this Storyboard timeline tree for use across threads" (Visual Studio Developper's Center)
- Storyboard で飛び跳ねるボール
[2013/3/18 追記] 結局プロパティの変化を捕まえて、毎回コードビハインドでStoryboardから作る方法で逃げた
Storyboard LastStoryboard; double from, to; void BeginHeightAnimation() { if (LastStoryboard != null) LastStoryboard.Stop(); ControlTemplate template = (ControlTemplate)GetValue(TemplateProperty); FrameworkElement target = (FrameworkElement)template.FindName("Target", this); DoubleAnimation dblAnim = new DoubleAnimation(from, to, new Duration(TimeSpan.FromMilliseconds(200))); Storyboard sb = new Storyboard(); sb.Children.Add(dblAnim); Storyboard.SetTarget(dblAnim, target); Storyboard.SetTargetProperty(dblAnim, new PropertyPath(FrameworkElement.HeightProperty)); sb.Begin(); LastStoryboard = sb; }
Comments