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ではうまく行かず。
[参考]
[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