Sugerencias y trucos para animacionesAnimation Tips and Tricks

Cuando se trabaja con animaciones en WPFWPF, hay una serie de sugerencias y trucos que pueden realizar las animaciones tienen un mejor rendimiento y evitar muchas frustraciones.When working with animations in WPFWPF, there are a number of tips and tricks that can make your animations perform better and save you frustration.

Problemas generalesGeneral Issues

Al animar la posición de una barra de desplazamiento o de un control deslizante, se inmovilizaAnimating the Position of a Scroll Bar or Slider Freezes It

Si anima la posición de una barra de desplazamiento o el control deslizante utilizando una animación que tiene un FillBehavior de HoldEnd (el valor predeterminado), el usuario ya no podrá mover la barra de desplazamiento o el control deslizante.If you animate the position of a scroll bar or slider using an animation that has a FillBehavior of HoldEnd (the default value), the user will no longer be able to move the scroll bar or slider. Esto se debe a que, aunque la animación finaliza, continúa invalidando el valor base de la propiedad de destino.That's because, even though the animation ended, it's still overriding the target property's base value. Para detener la animación de reemplazar el valor actual de la propiedad, quítelo o asignarle un FillBehavior de Stop.To stop the animation from overriding the property's current value, remove it, or give it a FillBehavior of Stop. Para obtener más información y un ejemplo, vea establece una propiedad después de la animación con un guión gráfico.For more information and an example, see Set a Property After Animating It with a Storyboard.

Animar la salida de una animación no surte ningún efectoAnimating the Output of an Animation Has No Effect

No se puede animar ningún objeto que sea la salida de otra animación.You can't animate an object that is the output of another animation. Por ejemplo, si utiliza un ObjectAnimationUsingKeyFrames para animar la Fill de un Rectangle desde una RadialGradientBrush a una SolidColorBrush, no se puede animar cualquier propiedad de la RadialGradientBrush o SolidColorBrush.For example, if you use an ObjectAnimationUsingKeyFrames to animate the Fill of a Rectangle from a RadialGradientBrush to a SolidColorBrush, you can't animate any properties of the RadialGradientBrush or SolidColorBrush.

No se puede cambiar el valor de una propiedad después de animarlaCan't Change the Value of a Property after Animating it

En algunos casos, puede parecer que no es posible cambiar el valor de una propiedad después de animarla, incluso después de que la animación haya finalizado.In some cases, it might appear that you can't change the value of a property after it's been animated, even after the animation has ended. Esto se debe a que, aunque la animación finaliza, continúa invalidando el valor base de la propiedad.That's because, even though the animation ended, it's still overriding the property's base value. Para detener la animación de reemplazar el valor actual de la propiedad, quítelo o asignarle un FillBehavior de Stop.To stop the animation from overriding the property's current value, remove it, or give it a FillBehavior of Stop. Para obtener más información y un ejemplo, vea establece una propiedad después de la animación con un guión gráfico.For more information and an example, see Set a Property After Animating It with a Storyboard.

Cambiar una escala de tiempo no surte ningún efectoChanging a Timeline Has No Effect

Aunque la mayoría Timeline propiedades se pueden animar y pueden estar enlazado a datos, cambiar los valores de propiedad de un activo Timeline parece no tener ningún efecto.Although most Timeline properties are animatable and can be data bound, changing the property values of an active Timeline seems to have no effect. La razón es que, cuando un Timeline es iniciado, el sistema de control de tiempo realiza una copia de la Timeline y lo utiliza para crear un Clock objeto.That's because, when a Timeline is begun, the timing system makes a copy of the Timeline and uses it to create a Clock object. Modificar el original no surte ningún efecto en la copia del sistema.Modifying the original has no effect on the system's copy.

Para una Timeline para reflejar los cambios, debe volver a generar y utilizar para reemplazar el reloj previamente creado su reloj.For a Timeline to reflect changes, its clock must be regenerated and used to replace the previously created clock. Los relojes no se regeneran automáticamente.Clocks are not regenerated for you automatically. A continuación se muestran distintas maneras de aplicar cambios a las escalas de tiempo:The following are several ways to apply timeline changes:

  • Si la escala de tiempo es o pertenece a un Storyboard, puede hacer que reflejar los cambios puede volver a aplicar su guión gráfico utilizando una BeginStoryboard o Begin método.If the timeline is or belongs to a Storyboard, you can make it reflect changes by reapplying its storyboard using a BeginStoryboard or the Begin method. El efecto secundario de esta acción es que también se reinicia la animación.This has the side effect of also restarting the animation. En el código, puede utilizar el Seek volver del método para avanzar el guión gráfico en su posición anterior.In code, you can use the Seek method to advance the storyboard back to its previous position.

  • Si aplica una animación directamente a una propiedad mediante el BeginAnimation método, llame a la BeginAnimation nuevo al método y pásele la animación que se ha modificado.If you applied an animation directly to a property using the BeginAnimation method, call the BeginAnimation method again and pass it the animation that has been modified.

  • Si está trabajando directamente en el nivel de relojes, cree y aplique un nuevo conjunto de relojes y utilícelos para reemplazar el conjunto anterior de relojes generados.If you are working directly at the clock level, create and apply a new set of clocks and use them to replace the previous set of generated clocks.

Para obtener más información acerca de las escalas de tiempo y relojes, consulte animación y temporización información general del sistema.For more information about timelines and clocks, see Animation and Timing System Overview.

FillBehavior.Stop no funciona como se esperaFillBehavior.Stop Doesn't Work as Expected

Hay ocasiones al establecer el FillBehavior propiedad Stop parece no tener ningún efecto, como cuando una animación "entrega" a otra porque tiene un HandoffBehavior configuración de SnapshotAndReplace.There are times when setting the FillBehavior property to Stop seems to have no effect, such as when one animation "hands off" to another because it has a HandoffBehavior setting of SnapshotAndReplace.

En el ejemplo siguiente se crea un Canvas, Rectangle y TranslateTransform.The following example creates a Canvas, a Rectangle and a TranslateTransform. El TranslateTransform se animará para mover el Rectangle alrededor de la Canvas.The TranslateTransform will be animated to move the Rectangle around the Canvas.

<Canvas Width="600" Height="200">
  <Rectangle 
    Canvas.Top="50" Canvas.Left="0" 
    Width="50" Height="50" Fill="Red">
    <Rectangle.RenderTransform>
      <TranslateTransform 
        x:Name="MyTranslateTransform" 
        X="0" Y="0" />
    </Rectangle.RenderTransform>
  </Rectangle>
</Canvas>

Los ejemplos de esta sección utilizan los objetos anteriores para demostrar varios casos donde la FillBehavior propiedad no se comporta como cabría esperar que.The examples in this section use the preceding objects to demonstrate several cases where the FillBehavior property doesn't behave as you might expect it to.

FillBehavior="Stop" y HandoffBehavior con varias animacionesFillBehavior="Stop" and HandoffBehavior with Multiple Animations

A veces, parece como si una animación omitiese su FillBehavior propiedad cuando se reemplaza por una segunda animación.Sometimes it seems as though an animation ignores its FillBehavior property when it is replaced by a second animation. Considere el ejemplo siguiente, que se crea dos Storyboard objetos y los utiliza para animar el mismo TranslateTransform se muestra en el ejemplo anterior.Take the following example, which creates two Storyboard objects and uses them to animate the same TranslateTransform shown in the preceding example.

La primera Storyboard, B1, anima la X propiedad de la TranslateTransform de 0 a 350, que mueve el rectángulo 350 píxeles a la derecha.The first Storyboard, B1, animates the X property of the TranslateTransform from 0 to 350, which moves the rectangle 350 pixels to the right. Cuando llega al final de su duración de la animación y detiene la reproducción, la X propiedad revierte a su valor original, 0.When the animation reaches the end of its duration and stops playing, the X property reverts to its original value, 0. Como resultado, el rectángulo se mueve 350 píxeles a la derecha y luego salta para situarse en su posición original.As a result, the rectangle moves to the right 350 pixels and then jumps back to its original position.

<Button Content="Start Storyboard B1">
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Click">
      <BeginStoryboard>
        <Storyboard x:Name="B1">
          <DoubleAnimation 
            Storyboard.TargetName="MyTranslateTransform"
            Storyboard.TargetProperty="X"
            From="0" To="350" Duration="0:0:5"
            FillBehavior="Stop"
            />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Button.Triggers>
</Button>

El segundo Storyboard, B2, también anima la X propiedad del mismo TranslateTransform.The second Storyboard, B2, also animates the X property of the same TranslateTransform. Dado que solo el To propiedad de la animación en este Storyboard está establecido, la animación usa el valor actual de la propiedad que anima como su valor inicial.Because only the To property of the animation in this Storyboard is set, the animation uses the current value of the property it animates as its starting value.


<!-- Animates the same object and property as the preceding
     Storyboard. -->
<Button Content="Start Storyboard B2">
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Click">
      <BeginStoryboard>
        <Storyboard x:Name="B2">
          <DoubleAnimation 
            Storyboard.TargetName="MyTranslateTransform"
            Storyboard.TargetProperty="X"
            To="500" Duration="0:0:5" 
            FillBehavior="Stop" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Button.Triggers>
</Button>

Si hace clic en el segundo botón mientras la primera Storyboard está reproduciendo, cabría esperar el siguiente comportamiento:If you click the second button while the first Storyboard is playing, you might expect the following behavior:

  1. El primer guión gráfico finaliza y envía el rectángulo a su posición original, porque la animación tiene una FillBehavior de Stop.The first storyboard ends and sends the rectangle back to its original position, because the animation has a FillBehavior of Stop.

  2. El segundo guion gráfico se lleva a efecto y anima el objeto a partir de la posición actual, que ahora es 0, hasta 500.The second storyboard takes effect and animates from the current position, which is now 0, to 500.

Pero esto no es lo que sucede.But that's not what happens. En lugar de ello, el rectángulo no salta a su posición original, sino que continúa moviéndose a la derecha.Instead, the rectangle does not jump back; it continues moving to the right. Esto se debe a que la segunda animación utiliza el valor actual de la primera animación como su valor inicial y anima desde ese valor hasta 500.That's because the second animation uses the current value of the first animation as its starting value and animates from that value to 500. Cuando la segunda animación reemplaza la primera porque la SnapshotAndReplace HandoffBehavior se utiliza, el FillBehavior de la primera animación no tiene importancia.When the second animation replaces the first because the SnapshotAndReplaceHandoffBehavior is used, the FillBehavior of the first animation does not matter.

FillBehavior y el evento CompletedFillBehavior and the Completed Event

En los ejemplos siguientes se muestran otro escenario en el que el Stop FillBehavior parece no tener ningún efecto.The next examples demonstrate another scenario in which the StopFillBehavior seems to have no effect. Una vez más, en el ejemplo se utiliza un guión gráfico para animar la X propiedad de la TranslateTransform de 0 a 350.Again, the example uses a Storyboard to animate the X property of the TranslateTransform from 0 to 350. Sin embargo, esta vez en el ejemplo se registra para el Completed eventos.However, this time the example registers for the Completed event.

<Button Content="Start Storyboard C">
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Click">
      <BeginStoryboard>
        <Storyboard Completed="StoryboardC_Completed">
          <DoubleAnimation 
            Storyboard.TargetName="MyTranslateTransform"
            Storyboard.TargetProperty="X"
            From="0" To="350" Duration="0:0:5"
            FillBehavior="Stop" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Button.Triggers>
</Button>

El Completed controlador de eventos inicia otro Storyboard que anima la misma propiedad de su valor actual en 500.The Completed event handler starts another Storyboard that animates the same property from its current value to 500.

private void StoryboardC_Completed(object sender, EventArgs e)
{

    Storyboard translationAnimationStoryboard =
        (Storyboard)this.Resources["TranslationAnimationStoryboardResource"];
    translationAnimationStoryboard.Begin(this);
}
Private Sub StoryboardC_Completed(ByVal sender As Object, ByVal e As EventArgs)

	Dim translationAnimationStoryboard As Storyboard = CType(Me.Resources("TranslationAnimationStoryboardResource"), Storyboard)
	translationAnimationStoryboard.Begin(Me)
End Sub

Éste es el marcado que define el segundo Storyboard como un recurso.The following is the markup that defines the second Storyboard as a resource.

<Page.Resources>
  <Storyboard x:Key="TranslationAnimationStoryboardResource">
    <DoubleAnimation 
      Storyboard.TargetName="MyTranslateTransform"
      Storyboard.TargetProperty="X"
      To="500" Duration="0:0:5" />
  </Storyboard>
</Page.Resources>

Al ejecutar el Storyboard, que cabría esperar el X propiedad de la TranslateTransform para animar de 0 a 350, a continuación, volver a 0 después de completar (porque tiene un FillBehavior de Stop) y, a continuación, animar entre 0 y 500.When you run the Storyboard, you might expect the X property of the TranslateTransform to animate from 0 to 350, then revert to 0 after it completes (because it has a FillBehavior setting of Stop), and then animate from 0 to 500. En su lugar, el TranslateTransform anima desde 0 a 350 y, a continuación, en 500.Instead, the TranslateTransform animates from 0 to 350 and then to 500.

Eso es debido al orden en el que WPFWPF desencadena eventos y porque los valores de propiedad se almacenan en caché y no se vuelven a calcular a menos que se invalide la propiedad.That's because of the order in which WPFWPF raises events and because property values are cached and are not recalculated unless the property is invalidated. El Completed evento se procesa en primer lugar porque se activó por la escala de tiempo raíz (el primer Storyboard).The Completed event is processed first because it was triggered by the root timeline (the first Storyboard). En este momento, el X propiedad todavía devuelve su valor animado porque todavía no han invalidado todavía.At this time, the X property still returns its animated value because it hasn't been invalidated yet. El segundo Storyboard utiliza el valor almacenado en caché como su valor inicial y comienza la animación.The second Storyboard uses the cached value as its starting value and begins animating.

RendimientoPerformance

Las animaciones siguen ejecutándose después de salir de una páginaAnimations Continue to Run After Navigating Away from a Page

Cuando se desplaza fuera de un Page que contiene animaciones en ejecución, las animaciones continuarán reproducir hasta el Page recolección.When you navigate away from a Page that contains running animations, those animations will continue to play until the Page is garbage collected. Según el sistema de navegación que se utilice, la página de la que ha salido al navegar podría permanecer en memoria por tiempo indefinido, durante el cual seguiría consumiendo recursos con sus animaciones.Depending on the navigation system you're using, a page that you navigate away from might stay in memory for an indefinite amount of time, all the while consuming resources with its animations. Esto resulta especialmente patente cuando una página contiene animaciones de ejecución continua ("ambiente").This is most noticeable when a page contains constantly running ("ambient") animations.

Por esta razón, es una buena idea usar el Unloaded evento quite animaciones al salir de una página.For this reason, it's a good idea to use the Unloaded event to remove animations when you navigate away from a page.

Hay diferentes maneras de quitar una animación.There are different ways to remove an animation. Pueden emplear las técnicas siguientes para quitar las animaciones que pertenecen a un Storyboard.The following techniques can be used to remove animations that belong to a Storyboard.

La técnica siguiente se puede utilizar sin tener en cuenta cómo se inició la animación.The next technique may be used regardless of how the animation was started.

  • Para quitar las animaciones de una propiedad específica, use la BeginAnimation(DependencyProperty, AnimationTimeline) método.To remove animations from a specific property, use the BeginAnimation(DependencyProperty, AnimationTimeline) method. Especifique la propiedad que se está animada como el primer parámetro, y null como el segundo.Specify the property being animated as the first parameter, and null as the second. De este modo, se quitarán todos los relojes de animación de la propiedad.This will remove all animation clocks from the property.

Para obtener más información sobre las distintas maneras para animar propiedades, consulte Property Animation Techniques Overview.For more information about the different ways to animate properties, see Property Animation Techniques Overview.

Utilizar el valor Compose de HandoffBehavior consume recursos del sistemaUsing the Compose HandoffBehavior Consumes System Resources

Al aplicar un Storyboard, AnimationTimeline, o AnimationClock a una propiedad mediante el Compose HandoffBehavior, cualquier Clock objetos asociados anteriormente a esa propiedad siguen consumiendo recursos del sistema; el sistema de temporización no transmitirá Quite estos relojes automáticamente.When you apply a Storyboard, AnimationTimeline, or AnimationClock to a property using the ComposeHandoffBehavior, any Clock objects previously associated with that property continue to consume system resources; the timing system will not remove these clocks automatically.

Para evitar problemas de rendimiento cuando se aplica un gran número de relojes con Compose, debe quitar los relojes de composición de la propiedad animada cuando se hayan completado.To avoid performance issues when you apply a large number of clocks using Compose, you should remove composing clocks from the animated property after they complete. Hay varias formas de quitar un reloj.There are several ways to remove a clock.

Este problema se produce principalmente en las animaciones de objetos que tienen un período de duración prolongado.This is primarily an issue for animations on objects that have a long lifetime. Cuando un objeto se recolecta como elemento no utilizado, sus relojes también se desconectan y se recolectan como elementos no utilizados.When an object is garbage collected, its clocks will also be disconnected and garbage collected.

Para obtener más información acerca de los objetos de reloj, consulte animación y temporización información general del sistema.For more information about clock objects, see Animation and Timing System Overview.

Vea tambiénSee Also

Información general sobre animacionesAnimation Overview