删除故事板但保持动画值?

时间:2009-11-05 22:39:44

标签: wpf animation storyboard datatrigger

如何在XAML中删除故事板(即DataTrigger中的RemoveStoryboard操作),但保留已设置动画的值。与Animatable.BeginAnimation类似:

  

如果动画的BeginTime为空,则将删除任何当前动画,并保留属性的当前值。

2 个答案:

答案 0 :(得分:4)

RemoveStoryboard的主要用途是删除动画值并将其设置回未动画状态。在大多数情况下,您可以将调用切换到PauseStoryboard或StopStoryboard,具体取决于具体情况。唯一的例外是当您需要释放故事板所持有的资源或将其用于其他目的时。

如果您确实要删除故事板并保留属性值,则必须直接在属性上设置动画值。这可以通过将每个值设置为动画值来完成,如下所示:

void CopyAnimatedValuesToLocalValues(DependencyObject obj)
{
  // Recurse down tree
  for(int i=0; i<VisualTreeHelper.GetChildrenCount(obj); i++)
    CopyAnimatedValuesToLocalValues(VisualTreeHelper.GetChild(obj, i));

  var enumerator = obj.GetLocalValueEnumerator();
  while(enumerator.MoveNext())
  {
    var prop = enumerator.Current.Property;
    var value = enumerator.Current.Value as Freezable;

    // Recurse into eg. brushes that may be set by storyboard, as long as they aren't frozen
    if(value!=null && !value.IsFrozen)
      CopyAnimatedValuesToLocalValues(value);

    // *** This is the key bit of code ***
    if(DependencyPropertyHelper.GetValueSource(obj, prop).IsAnimated)
      obj.SetValue(prop, obj.GetValue(prop));

  }
}

在删除故事板以复制动画值之前,请先调用此方法。

编辑有人评论此代码可能是不必要的,因为使用BeginTime = null调用BeginAnimation会产生类似的效果。

虽然使用BeginTime = null的BeginAnimation使得它看起来好像将值复制到本地,但稍后调用RemoveStoryboard将导致值恢复。这是因为具有BeginTime = null的BeginAnimation导致先前动画在新动画开始之前保持其值,但不会影响本地值。

上面的代码实际上会覆盖本地值,因此可以删除所有动画,并且对象仍将具有新值。因此,如果你真的想调用RemoveStoryboard并仍然保留你的值,你需要我上面写的代码或类似的代码。

答案 1 :(得分:1)

使用AnimationTimeline时遇到了类似的问题。最简单的解决方案是在后面的代码中捕获Completed事件,并在使用BeginAnimation参数调用null之前删除动画,获取属性的当前值并使用它来设置它

这将获取最后一个动画值,然后设置它。

void OnCompleted( object sender, EventArgs args )
{
    // Required to copy latest animated value to local value.
    o.SomeValue = o.SomeValue;
    o.BeginAnimation( SomeClass.SomeValueProperty, null );
}