Retire del guión gráfico, pero mantener el valor de animación?
-
18-09-2019 - |
Pregunta
¿Cómo puedo eliminar un guión gráfico en XAML (acción RemoveStoryboard es decir, en un DataTrigger) pero mantener el valor que se ha animado. Al igual que en el Animatable.BeginAnimation :
Si BeginTime de la animación es nulo, las animaciones actuales serán eliminados y se llevará a cabo el valor actual de la propiedad.
Solución
El uso principal de RemoveStoryboard es eliminar los valores animados y establecer de nuevo a su estado no animada. En la mayoría de los casos basta con cambiar la llamada a PauseStoryboard o StopStoryboard lugar, dependiendo del caso específico. La única excepción es cuando se necesita para liberar los recursos mantenidos por el guión gráfico o utilizarla para otro propósito.
Si realmente desea eliminar el guión gráfico y mantener los valores de la propiedad, debe establecer los valores de animación directamente en las propiedades. Esto se puede hacer mediante el establecimiento de cada valor con el valor de animación, algo como esto:
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));
}
}
Llamada este derecho antes de quitar el guión gráfico para copiar los valores animados.
Editar Se hizo un comentario que este código puede ser innecesario porque llamando BeginAnimation con BeginTime = null logra un efecto similar.
Si bien es cierto que con BeginAnimation BeginTime = null hace parece como si los valores se copian en locales, una llamada posterior a RemoveStoryboard hará que los valores que se revierten. Esto se debe a BeginAnimation con BeginTime = null provoca la animación antes de mantener sus valores pendientes del inicio de la nueva animación, pero no hace nada para afectar a los valores locales.
El código anterior en realidad sobrescribe los valores locales, por lo que todas las animaciones pueden ser retirados y los objetos todavía tendrán sus nuevos valores. Así que si realmente desea llamar RemoveStoryboard y aún así mantener sus valores, necesitará el código que escribí más arriba o algo parecido.
Otros consejos
Yo tenía un problema similar cuando se utiliza AnimationTimeline
. La solución más fácil resultó ser captura el evento Completed
en código detrás y antes de llamar BeginAnimation
con el parámetro null
para eliminar la animación, obtener el valor actual de la propiedad y el uso que para configurarlo.
Esto nos lleva al último valor de animación, y lo establece.
void OnCompleted( object sender, EventArgs args )
{
// Required to copy latest animated value to local value.
o.SomeValue = o.SomeValue;
o.BeginAnimation( SomeClass.SomeValueProperty, null );
}