Удалить раскадровку, но сохранить анимированную ценность?


Как удалить раскадровку в XAML (то есть действие RemoveStoryboard в DataTrigger), но сохранить значение, которое было анимировано. Аналогично Анимируемому.BeginAnimation :

Если начальное время анимации равно нулю, то все текущие анимации будут удалены и сохранится текущее значение свойства.

2 10

2 ответа:

Основное применение 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));

  }
}

Вызовите это прямо перед удалением раскадровки, чтобы скопировать анимированные значения.

Edit было сделано замечание, что этот код может быть ненужным, поскольку вызов BeginAnimation с BeginTime=null достигает аналогичного эффекта.

Хотя верно, что BeginAnimation с BeginTime=null делает его похожим на то, что значения были скопированы в local, более поздний вызов RemoveStoryboard будет заставьте значения вернуться. Это происходит потому, что BeginAnimation с BeginTime=null заставляет предыдущую анимацию удерживать свои значения до начала новой анимации, но не влияет на локальные значения.

Приведенный выше код фактически перезаписывает локальные значения, поэтому все анимации могут быть удалены, и объекты по-прежнему будут иметь свои новые значения. Поэтому, если вы действительно хотите вызвать RemoveStoryboard и сохранить свои значения, вам понадобится код, который я написал выше, или что-то подобное.

У меня была аналогичная проблема при использовании 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 );
}