Conseils et astuces sur les animations

Lorsque vous travaillez avec des animations dans WPF, il existe un certain nombre de conseils et astuces qui peuvent améliorer vos animations et vous sauver la frustration.

Problèmes généraux

L’animation de la position d’une barre de défilement ou d’un curseur bloque cet élément

Si vous animez la position d’une barre de défilement ou d’un curseur à l’aide d’une animation dont la FillBehaviorHoldEnd valeur par défaut est définie, l’utilisateur ne pourra plus déplacer la barre de défilement ou le curseur. Cela survient car l’animation, même si elle est terminée, remplace toujours la valeur de base de la propriété cible. Pour empêcher l’animation de remplacer la valeur actuelle de la propriété, supprimez-la ou donnez-la .FillBehaviorStop Pour plus d’informations et un exemple, consultez Définir une propriété après l'avoir animée avec un storyboard.

L’animation de la sortie d’une animation n’a aucun effet

Vous ne pouvez pas animer un objet qui est le résultat d’une autre animation. Par exemple, si vous utilisez un ObjectAnimationUsingKeyFrames pour animer l’un Fill d’un RectangleRadialGradientBrush à un SolidColorBrush, vous ne pouvez animer aucune propriété du RadialGradientBrush ou SolidColorBrush.

Impossible de modifier la valeur d’une propriété après l’avoir animée

Dans certains cas, il peut sembler que vous ne pouvez pas modifier la valeur d’une propriété une fois qu’elle a été animée, même une fois l’animation terminée. Cela survient car l’animation, même si elle est terminée, remplace toujours la valeur de base de la propriété. Pour empêcher l’animation de remplacer la valeur actuelle de la propriété, supprimez-la ou donnez-la .FillBehaviorStop Pour plus d’informations et un exemple, consultez Définir une propriété après l'avoir animée avec un storyboard.

La modification d’une chronologie n’a aucun effet

Bien que la plupart des Timeline propriétés soient animatables et peuvent être liées aux données, la modification des valeurs de propriété d’un actif Timeline semble n’avoir aucun effet. C’est parce que, lorsqu’un est Timeline commencé, le système de minutage effectue une copie de l’objet Timeline et l’utilise pour créer un Clock objet. La modification de l’original n’a aucun effet sur la copie du système.

Pour qu’il Timeline reflète les modifications, son horloge doit être régénérée et utilisée pour remplacer l’horloge créée précédemment. Les horloges ne sont pas régénérées automatiquement pour vous. Voici plusieurs façons d’appliquer des modifications de chronologie :

  • Si le chronologie est ou appartient à un Storyboard, vous pouvez le faire refléter en réappliquer son storyboard à l’aide d’une BeginStoryboard ou de la Begin méthode. Cela a pour effet secondaire de redémarrer également l’animation. Dans le code, vous pouvez utiliser la Seek méthode pour ramener le storyboard à sa position précédente.

  • Si vous avez appliqué une animation directement à une propriété à l’aide de la BeginAnimation méthode, appelez à nouveau la BeginAnimation méthode et transmettez-la à l’animation qui a été modifiée.

  • Si vous travaillez directement au niveau de l’horloge, créez et appliquez un nouveau jeu d’horloges et utilisez-le pour remplacer le précédent jeu d’horloges généré.

Pour plus d’informations sur les horloges et les chronologies, consultez Vue d'ensemble de l'animation et du système de minutage.

FillBehavior.Stop ne fonctionne pas comme prévu

Il existe des moments où la définition de la FillBehavior propriété ne Stop semble pas avoir d’effet, par exemple lorsqu’une animation « se remet » à une autre parce qu’elle a un HandoffBehavior paramètre de SnapshotAndReplace.

L’exemple suivant crée un Canvas, a Rectangle et un TranslateTransform. Le TranslateTransform sera animé pour déplacer le Rectangle autour du 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>

Les exemples de cette section utilisent les objets précédents pour illustrer plusieurs cas où la FillBehavior propriété ne se comporte pas comme prévu.

FillBehavior="Stop" et HandoffBehavior avec plusieurs animations

Parfois, il semble que l’animation ignore sa FillBehavior propriété lorsqu’elle est remplacée par une deuxième animation. Prenez l’exemple suivant, qui crée deux Storyboard objets et les utilise pour animer les mêmes TranslateTransform éléments illustrés dans l’exemple précédent.

Le premier Storyboard, anime B1la X propriété du TranslateTransform 0 à 350, qui déplace le rectangle de 350 pixels à droite. Lorsque l’animation atteint la fin de sa durée et cesse de jouer, la X propriété revient à sa valeur d’origine, 0. Par conséquent, le rectangle se déplace vers la droite de 350 pixels puis revient à sa position d’origine.

<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>

Le deuxième Storyboard, B2anime également la X propriété du même TranslateTransform. Étant donné que seule la To propriété de l’animation dans ce Storyboard jeu est définie, l’animation utilise la valeur actuelle de la propriété qu’elle anime comme valeur de départ.


<!-- 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 vous cliquez sur le deuxième bouton pendant la première Storyboard lecture, vous pouvez vous attendre au comportement suivant :

  1. Le premier storyboard se termine et renvoie le rectangle à sa position d’origine, car l’animation a une valeur FillBehaviorStop.

  2. Le deuxième storyboard est appliqué et s’anime à partir de la position actuelle, qui est désormais 0, jusqu'à 500.

Mais ce n’est pas ce qui se produit. Au lieu de cela, le rectangle ne revient pas. Il continue à se déplacer vers la droite. Cela se produit car la deuxième animation utilise la valeur actuelle de la première animation comme valeur de départ, et anime à partir de cette valeur à 500. Lorsque la deuxième animation remplace la première, car elle SnapshotAndReplaceHandoffBehavior est utilisée, la FillBehavior première animation n’a pas d’importance.

FillBehavior et l’événement terminé

Les exemples suivants illustrent un autre scénario dans lequel le scénario StopFillBehavior semble ne pas avoir d’effet. Là encore, l’exemple utilise un Storyboard pour animer la X propriété de TranslateTransform 0 à 350. Toutefois, cette fois, l’exemple s’inscrit pour l’événement Completed .

<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>

Le Completed gestionnaire d’événements démarre une autre Storyboard propriété qui anime la même propriété de sa valeur actuelle à 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

Voici le balisage qui définit la seconde Storyboard en tant que ressource.

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

Lorsque vous exécutez le Storyboard, vous pouvez vous attendre à ce que la X propriété de l’animation TranslateTransform entre 0 et 350, puis revenir à 0 une fois terminée (car elle a un FillBehavior paramètre ), Stoppuis animer de 0 à 500. Au lieu de cela, les TranslateTransform animations sont comprises entre 0 et 350, puis 500.

Cela est dû à l’ordre dans lequel WPF déclenche des événements et parce que les valeurs de propriété sont mises en cache et ne sont pas recalculées, sauf si la propriété est invalidée. L’événement Completed est traité en premier, car il a été déclenché par le chronologie racine (le premierStoryboard). À ce stade, la X propriété retourne toujours sa valeur animée, car elle n’a pas encore été invalidée. La deuxième Storyboard utilise la valeur mise en cache comme valeur de départ et commence à animer.

Performances

Les animations continuent à s’exécuter après avoir quitté une page

Lorsque vous quittez une Page animation qui contient des animations en cours d’exécution, ces animations continueront à être lues jusqu’à ce que la Page mémoire soit collectée. Selon le système de navigation vous utilisez, une page que vous quittez peut rester en mémoire pendant une durée indéterminée tout en consommant des ressources avec ses animations. Cela est particulièrement visible lorsqu’une page contient des animations en exécution constante (« ambiantes »).

Pour cette raison, il est judicieux d’utiliser l’événement Unloaded pour supprimer des animations lorsque vous quittez une page.

Il existe différentes manières de supprimer une animation. Les techniques suivantes peuvent être utilisées pour supprimer des animations qui appartiennent à un Storyboard.

La technique suivante peut être utilisée, quelle que soit la façon dont l’animation a été démarrée.

  • Pour supprimer des animations d’une propriété spécifique, utilisez la BeginAnimation(DependencyProperty, AnimationTimeline) méthode. Spécifiez la propriété animée comme premier paramètre et null comme seconde. Cela supprimera toutes les horloges d’animation de la propriété.

Pour plus d’informations sur les différentes façons d’animer des propriétés, consultez Vue d'ensemble des techniques d'animation de propriétés.

L’utilisation de la composition HandoffBehavior consomme des ressources système

Lorsque vous appliquez un Storyboard, AnimationTimelineou AnimationClock à une propriété à l’aide du ComposeHandoffBehavior, tous Clock les objets précédemment associés à cette propriété continuent à consommer des ressources système ; le système de minutage ne supprime pas automatiquement ces horloges.

Pour éviter les problèmes de performances lorsque vous appliquez un grand nombre d’horloges à l’aide Compose, vous devez supprimer les horloges de composition de la propriété animée une fois qu’elles ont été terminées. Il existe plusieurs manières de supprimer une horloge.

Il s’agit principalement d’un problème pour les animations sur des objets qui ont une durée de vie longue. Lorsqu’un objet est récupéré par le garbage collector, ses horloges sont également déconnectées et récupérées.

Pour plus d’informations sur les objets d’horloge, consultez Vue d'ensemble de l'animation et du système de minutage.

Voir aussi