Suggerimenti sulle animazioniAnimation Tips and Tricks

Quando si lavora con le animazioni in WPF, sono disponibili numerosi suggerimenti e consigli che consentono di migliorare le prestazioni delle animazioni e di risparmiare.When working with animations in WPF, there are a number of tips and tricks that can make your animations perform better and save you frustration.

Problemi generaliGeneral Issues

Blocco di una barra di scorrimento o di un dispositivo di scorrimento se si anima la relativa posizioneAnimating the Position of a Scroll Bar or Slider Freezes It

Se si anima la posizione di una barra di scorrimento o di un dispositivo di scorrimento usando un'animazione con FillBehavior di HoldEnd (valore predefinito), l'utente non sarà più in grado di spostare la barra di scorrimento o il dispositivo di scorrimento.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. Ciò è dovuto al fatto che, anche se l'animazione è terminata, l'override del valore di base della proprietà di destinazione è ancora in corso.That's because, even though the animation ended, it's still overriding the target property's base value. Per arrestare l'override del valore corrente della proprietà da parte dell'animazione, rimuoverla o assegnarle una FillBehavior di Stop.To stop the animation from overriding the property's current value, remove it, or give it a FillBehavior of Stop. Per ulteriori informazioni e un esempio, vedere impostare una proprietà dopo averla animata con uno storyboard.For more information and an example, see Set a Property After Animating It with a Storyboard.

Animazione dell'output di un'animazione senza alcun effettoAnimating the Output of an Animation Has No Effect

Non è possibile animare un oggetto che rappresenta l'output di un'altra animazione.You can't animate an object that is the output of another animation. Se ad esempio si usa un ObjectAnimationUsingKeyFrames per animare il Fill di un Rectangle da un RadialGradientBrush a un SolidColorBrush, non è possibile aggiungere un'animazione a qualsiasi proprietà del 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.

Impossibile modificare il valore di una proprietà dopo averla animataCan't Change the Value of a Property after Animating it

In alcuni casi può sembrare che non sia possibile modificare il valore di una proprietà dopo che è stata animata, anche dopo il termine dell'animazione.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. Ciò è dovuto al fatto che, anche se l'animazione è terminata, l'override del valore di base della proprietà è ancora in corso.That's because, even though the animation ended, it's still overriding the property's base value. Per arrestare l'override del valore corrente della proprietà da parte dell'animazione, rimuoverla o assegnarle una FillBehavior di Stop.To stop the animation from overriding the property's current value, remove it, or give it a FillBehavior of Stop. Per ulteriori informazioni e un esempio, vedere impostare una proprietà dopo averla animata con uno storyboard.For more information and an example, see Set a Property After Animating It with a Storyboard.

Modifica di una sequenza temporale senza alcun effettoChanging a Timeline Has No Effect

Sebbene la maggior parte delle proprietà Timeline sia animata e possa essere associata ai dati, la modifica dei valori delle proprietà di un Timeline attivo sembra non avere alcun effetto.Although most Timeline properties are animatable and can be data bound, changing the property values of an active Timeline seems to have no effect. Questo perché, quando viene avviato un Timeline, il sistema di temporizzazione esegue una copia del Timeline e lo usa per creare un oggetto Clock.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. La modifica dell'originale non ha alcun effetto sulla copia del sistema.Modifying the original has no effect on the system's copy.

Affinché un Timeline rifletta le modifiche, è necessario rigenerare il relativo clock e usarlo per sostituire il Clock creato in precedenza.For a Timeline to reflect changes, its clock must be regenerated and used to replace the previously created clock. Gli orologi non vengono rigenerati automaticamente.Clocks are not regenerated for you automatically. Di seguito vengono indicate diverse modalità per applicare le modifiche alla sequenza temporale:The following are several ways to apply timeline changes:

  • Se la sequenza temporale è o appartiene a una Storyboard, è possibile fare in modo che rifletta le modifiche riapplicando il relativo storyboard usando un BeginStoryboard o il metodo Begin.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. Come effetto collaterale, l'animazione viene riavviata.This has the side effect of also restarting the animation. Nel codice è possibile usare il metodo Seek per far tornare lo storyboard alla posizione precedente.In code, you can use the Seek method to advance the storyboard back to its previous position.

  • Se un'animazione è stata applicata direttamente a una proprietà usando il metodo BeginAnimation, chiamare di nuovo il metodo BeginAnimation e passargli l'animazione che è stata modificata.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.

  • Se si lavora direttamente a livello di orologio, creare e applicare un nuovo set di orologi e usarli per sostituire il set di orologi generati in precedenza.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.

Per altre informazioni sulle sequenze temporali e sugli orologi, vedere Cenni preliminari sull'animazione e sul sistema di temporizzazione.For more information about timelines and clocks, see Animation and Timing System Overview.

Funzionamento imprevisto di FillBehavior.StopFillBehavior.Stop Doesn't Work as Expected

In alcuni casi, quando si imposta la proprietà FillBehavior su Stop sembra che non abbia alcun effetto, ad esempio quando un'animazione passa a un'altra, perché ha un'impostazione HandoffBehavior di 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.

Nell'esempio seguente vengono creati un Canvas, un Rectangle e un TranslateTransform.The following example creates a Canvas, a Rectangle and a TranslateTransform. La TranslateTransform verrà animata per spostare il Rectangle intorno al 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>

Negli esempi di questa sezione vengono usati gli oggetti precedenti per illustrare diversi casi in cui la proprietà FillBehavior non si comporta come previsto.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" e HandoffBehavior con animazioni multipleFillBehavior="Stop" and HandoffBehavior with Multiple Animations

Talvolta sembra che un'animazione ignori la relativa proprietà FillBehavior quando viene sostituita da una seconda animazione.Sometimes it seems as though an animation ignores its FillBehavior property when it is replaced by a second animation. Usare l'esempio seguente, che crea due oggetti Storyboard e li usa per animare lo stesso TranslateTransform illustrato nell'esempio precedente.Take the following example, which creates two Storyboard objects and uses them to animate the same TranslateTransform shown in the preceding example.

Il primo Storyboard, B1, aggiunge un'animazione alla proprietà X del TranslateTransform da 0 a 350, che sposta il rettangolo 350 pixel a destra.The first Storyboard, B1, animates the X property of the TranslateTransform from 0 to 350, which moves the rectangle 350 pixels to the right. Quando l'animazione raggiunge la fine della durata e interrompe la riproduzione, la proprietà X viene ripristinata sul valore originale, 0.When the animation reaches the end of its duration and stops playing, the X property reverts to its original value, 0. Il rettangolo di conseguenza si sposta a destra di 350 pixel e quindi torna alla posizione originale.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>

Il secondo Storyboard, B2, anima anche la proprietà X dello stesso TranslateTransform.The second Storyboard, B2, also animates the X property of the same TranslateTransform. Poiché è impostata solo la proprietà To dell'animazione in questo Storyboard, l'animazione usa il valore corrente della proprietà a cui viene aggiunta un'animazione come valore iniziale.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>

Se si fa clic sul secondo pulsante mentre viene riprodotta la prima Storyboard, è possibile prevedere il comportamento seguente:If you click the second button while the first Storyboard is playing, you might expect the following behavior:

  1. Il primo storyboard termina e invia nuovamente il rettangolo alla sua posizione originale, perché l'animazione dispone di un FillBehavior di Stop.The first storyboard ends and sends the rectangle back to its original position, because the animation has a FillBehavior of Stop.

  2. Il secondo storyboard viene applicato e viene animato dalla posizione corrente, da 0 a 500.The second storyboard takes effect and animates from the current position, which is now 0, to 500.

Questa situazioni non è quella che si verifica.But that's not what happens. Il rettangolo infatti non torna alla posizione originale ma continua a spostarsi a destra.Instead, the rectangle does not jump back; it continues moving to the right. Ciò accade perché la seconda animazione usa il valore corrente della prima animazione come valore iniziale e viene eseguita da tale valore fino a 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. Quando la seconda animazione sostituisce la prima perché viene utilizzata la SnapshotAndReplaceHandoffBehavior, il FillBehavior della prima animazione non è rilevante.When the second animation replaces the first because the SnapshotAndReplaceHandoffBehavior is used, the FillBehavior of the first animation does not matter.

FillBehavior ed evento CompletedFillBehavior and the Completed Event

Negli esempi successivi viene illustrato un altro scenario in cui il StopFillBehavior sembra non avere alcun effetto.The next examples demonstrate another scenario in which the StopFillBehavior seems to have no effect. Anche in questo caso, nell'esempio viene usato uno storyboard per animare la proprietà X della TranslateTransform da 0 a 350.Again, the example uses a Storyboard to animate the X property of the TranslateTransform from 0 to 350. Questa volta, tuttavia, l'esempio viene registrato per l'evento Completed.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>

Il gestore dell'evento Completed avvia un altro Storyboard che aggiunge un'animazione alla stessa proprietà dal valore corrente a 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

Di seguito è riportato il markup che definisce la seconda Storyboard come risorsa.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>

Quando si esegue la Storyboard, è possibile che la proprietà X della TranslateTransform venga animata da 0 a 350, quindi ripristinare 0 dopo il completamento (perché ha un'impostazione di FillBehavior di Stop), quindi aggiungere un'animazione da 0 a 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. Al contrario, il TranslateTransform aggiunge un'animazione da 0 a 350 e quindi a 500.Instead, the TranslateTransform animates from 0 to 350 and then to 500.

A causa dell'ordine in cui WPF genera eventi e perché i valori delle proprietà vengono memorizzati nella cache e non vengono ricalcolati, a meno che la proprietà non sia invalidata.That's because of the order in which WPF raises events and because property values are cached and are not recalculated unless the property is invalidated. L'evento Completed viene elaborato per primo perché è stato attivato dalla sequenza temporale radice (il primo Storyboard).The Completed event is processed first because it was triggered by the root timeline (the first Storyboard). A questo punto, la proprietà X restituisce comunque il valore animato perché non è ancora stata invalidata.At this time, the X property still returns its animated value because it hasn't been invalidated yet. Nel secondo Storyboard viene utilizzato il valore memorizzato nella cache come valore iniziale e viene avviata l'animazione.The second Storyboard uses the cached value as its starting value and begins animating.

PrestazioniPerformance

Continuazione dell'esecuzione delle animazioni dopo lo spostamento da una paginaAnimations Continue to Run After Navigating Away from a Page

Quando si esce da una Page che contiene animazioni in esecuzione, le animazioni continueranno a essere riprodotte fino a quando il Page non viene sottoposto a Garbage Collection.When you navigate away from a Page that contains running animations, those animations will continue to play until the Page is garbage collected. A seconda del sistema di navigazione in uso, una pagina da cui ci si è spostati potrebbe rimanere in memoria per un tempo indefinito, usando le risorse con le relative animazioni.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. Ciò è più evidente quando una pagina contiene animazioni in esecuzione continua.This is most noticeable when a page contains constantly running ("ambient") animations.

Per questo motivo, è consigliabile usare l'evento Unloaded per rimuovere le animazioni quando ci si sposta da una pagina.For this reason, it's a good idea to use the Unloaded event to remove animations when you navigate away from a page.

Per rimuovere un'animazione, sono disponibili modi diversi.There are different ways to remove an animation. È possibile utilizzare le tecniche seguenti per rimuovere le animazioni che appartengono a un Storyboard.The following techniques can be used to remove animations that belong to a Storyboard.

La tecnica successiva può essere usata indipendentemente dalla modalità di avviamento dell'animazione.The next technique may be used regardless of how the animation was started.

  • Per rimuovere le animazioni da una proprietà specifica, usare il metodo BeginAnimation(DependencyProperty, AnimationTimeline).To remove animations from a specific property, use the BeginAnimation(DependencyProperty, AnimationTimeline) method. Specificare la proprietà che viene animata come primo parametro e null come secondo.Specify the property being animated as the first parameter, and null as the second. In questo modo tutti gli orologi dell'animazione vengono rimossi dalla proprietà.This will remove all animation clocks from the property.

Per ulteriori informazioni sulle diverse modalità di animazione delle proprietà, vedere Cenni preliminari sulle tecniche di animazione delle proprietà.For more information about the different ways to animate properties, see Property Animation Techniques Overview.

Uso di Compose HandoffBehavior con risorse di sistemaUsing the Compose HandoffBehavior Consumes System Resources

Quando si applica un Storyboard, AnimationTimelineo AnimationClock a una proprietà utilizzando il HandoffBehaviorCompose, tutti gli oggetti Clock precedentemente associati a tale proprietà continuano a utilizzare le risorse di sistema. gli orologi non verranno rimossi automaticamente dal sistema di temporizzazione.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.

Per evitare problemi di prestazioni quando si applica un numero elevato di orologi usando Compose, è necessario rimuovere gli orologi di composizione dalla proprietà animata dopo che sono stati completati.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. Esistono diverse modalità di rimozione di un orologio.There are several ways to remove a clock.

Si tratta principalmente di un problema relativo alle animazioni su oggetti di lunga durata.This is primarily an issue for animations on objects that have a long lifetime. Quando un oggetto viene raccolto nel Garbage Collector, anche gli orologi vengono disconnessi e raccolti nel Garbage Collector stesso.When an object is garbage collected, its clocks will also be disconnected and garbage collected.

Per ulteriori informazioni sugli oggetti Clock, vedere Cenni preliminari sull'animazione e sul sistema di temporizzazione.For more information about clock objects, see Animation and Timing System Overview.

Vedere ancheSee also