Vue d'ensemble des storyboards

Cette rubrique montre comment utiliser Storyboard des objets pour organiser et appliquer des animations. Il décrit comment manipuler des objets de manière interactive Storyboard et décrit la syntaxe de ciblage de propriété indirecte.

Prérequis

Pour comprendre cette rubrique, vous devez connaître les différents types d’animations et leurs fonctions de base. Pour une introduction à l’animation, consultez Vue d’ensemble de l’animation. Vous devez également savoir comment utiliser les propriétés jointes. Pour plus d’informations sur les propriétés jointes, consultez Vue d’ensemble des propriétés jointes.

Qu’est-ce qu’un Storyboard ?

Les animations ne sont pas le seul type utile de chronologie. D’autres classes de chronologie sont fournies pour vous aider à organiser des jeux de chronologies et à appliquer des chronologies aux propriétés. Les chronologies de conteneur dérivent de la TimelineGroup classe et incluent ParallelTimeline et Storyboard .

Un Storyboard est un type de chronologie de conteneur qui fournit des informations de ciblage pour les chronologies qu’il contient. Une table de montage séquentiel peut contenir tout type de Timeline , y compris d’autres chronologies de conteneur et animations. Storyboard les objets vous permettent de combiner des chronologies qui affectent une variété d’objets et de propriétés dans une arborescence de chronologie unique, ce qui facilite l’organisation et le contrôle des comportements de minutage complexes. Par exemple, supposons que vous souhaitiez disposer d’un bouton qui effectue les trois opérations suivantes.

  • Développer et changer de couleur lorsque l’utilisateur sélectionne le bouton.

  • Réduire puis revenir à la taille normale lorsque l’utilisateur clique dessus.

  • Réduire et atténuer l’opacité en la définissant sur 50 % lorsque le bouton est désactivé.

Dans ce cas, vous avez plusieurs jeux d’animations qui s’appliquent au même objet, et vous souhaitez les jouer à différents moments, en fonction de l’état du bouton. Storyboard les objets vous permettent d’organiser les animations et de les appliquer dans des groupes à un ou plusieurs objets.

Où pouvez-vous utiliser une table de montage séquentiel ?

Un Storyboard peut être utilisé pour animer des propriétés de dépendance de classes pouvant être animées (pour plus d’informations sur ce qui rend une classe animable, consultez vue d’ensemblede l’animation). Toutefois, étant donné que le Storyboard est une fonctionnalité au niveau de l’infrastructure, l’objet doit appartenir au NameScope d’un ou d’un FrameworkElement FrameworkContentElement .

Par exemple, vous pouvez utiliser un Storyboard pour effectuer les opérations suivantes :

Toutefois, vous ne pouviez pas utiliser un Storyboard pour animer un SolidColorBrush qui n’a pas inscrit son nom avec un FrameworkElement ou un FrameworkContentElement , ou n’a pas été utilisé pour définir une propriété d’un ou d’un FrameworkElement FrameworkContentElement .

Comment appliquer des animations avec une table de montage séquentiel

Pour utiliser un Storyboard pour organiser et appliquer des animations, vous ajoutez les animations en tant que chronologies enfants de Storyboard . La Storyboard classe fournit les Storyboard.TargetName Storyboard.TargetProperty propriétés jointes et. Vous définissez ces propriétés sur une animation pour spécifier sa propriété et son objet cibles.

Pour appliquer des animations à leurs cibles, commencez l' Storyboard utilisation d’une action de déclencheur ou d’une méthode. Dans XAML , vous utilisez un BeginStoryboard objet avec un EventTrigger , Trigger ou DataTrigger . Dans le code, vous pouvez également utiliser la Begin méthode.

Le tableau suivant présente les différents emplacements où chaque Storyboard technique de début est prise en charge : par instance, style, modèle de contrôle et modèle de données. « Par instance » fait référence à la technique consistant à appliquer une animation ou une table de montage séquentiel directement aux instances d’un objet, plutôt qu’à un style, un modèle de contrôle ou un modèle de données.

La table de montage séquentiel démarre à l’aide de… Par instance Style Modèle de contrôle Modèle de données Exemple
BeginStoryboard et un EventTrigger Oui Oui Oui Oui Animer une propriété à l’aide d’une table de montage séquentiel
BeginStoryboard et une propriété Trigger Non Oui Oui Oui Déclencher une animation en cas de modification d’une valeur de propriété
BeginStoryboard et une propriété MultiTrigger Non Oui Oui Oui Exemple de classe MultiTrigger
BeginStoryboard et un DataTrigger Non Oui Oui Oui Comment : déclencher une animation en cas de modification de données
BeginStoryboard et un MultiDataTrigger Non Oui Oui Oui Exemple de classe MultiDataTrigger
Méthode Begin Oui Non Non Non Animer une propriété à l’aide d’une table de montage séquentiel

L’exemple suivant utilise un Storyboard pour animer le Width d’un Rectangle élément et le Color d’un SolidColorBrush utilisé pour peindre ce Rectangle .

<!-- This example shows how to animate with a storyboard.-->
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.Samples.Animation.StoryboardsExample" 
  WindowTitle="Storyboards Example">
  <StackPanel Margin="20">
    
    <Rectangle Name="MyRectangle"
      Width="100"
      Height="100">
      <Rectangle.Fill>
        <SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
      </Rectangle.Fill>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.MouseEnter">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimation 
                Storyboard.TargetName="MyRectangle"
                Storyboard.TargetProperty="Width"
                From="100" To="200" Duration="0:0:1" />
              
              <ColorAnimation 
                Storyboard.TargetName="MySolidColorBrush"
                Storyboard.TargetProperty="Color"
                From="Blue" To="Red" Duration="0:0:1" />  
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers>
    </Rectangle> 
  </StackPanel>
</Page>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Data;
using System.Windows.Shapes;
using System.Windows.Input;

namespace Microsoft.Samples.Animation
{
    public class StoryboardsExample : Page
    {
        public StoryboardsExample()
        {
            this.WindowTitle = "Storyboards Example";
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(20);

            Rectangle myRectangle = new Rectangle();
            myRectangle.Name = "MyRectangle";

            // Create a name scope for the page.
            NameScope.SetNameScope(this, new NameScope());

            this.RegisterName(myRectangle.Name, myRectangle);
            myRectangle.Width = 100;
            myRectangle.Height = 100;
            SolidColorBrush mySolidColorBrush = new SolidColorBrush(Colors.Blue);
            this.RegisterName("MySolidColorBrush", mySolidColorBrush);
            myRectangle.Fill = mySolidColorBrush;

            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 100;
            myDoubleAnimation.To = 200;
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
            Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
            Storyboard.SetTargetProperty(myDoubleAnimation,
                new PropertyPath(Rectangle.WidthProperty));

            ColorAnimation myColorAnimation = new ColorAnimation();
            myColorAnimation.From = Colors.Blue;
            myColorAnimation.To = Colors.Red;
            myColorAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
            Storyboard.SetTargetName(myColorAnimation, "MySolidColorBrush");
            Storyboard.SetTargetProperty(myColorAnimation,
                new PropertyPath(SolidColorBrush.ColorProperty));
            Storyboard myStoryboard = new Storyboard();
            myStoryboard.Children.Add(myDoubleAnimation);
            myStoryboard.Children.Add(myColorAnimation);

            myRectangle.MouseEnter += delegate(object sender, MouseEventArgs e)
            {
                myStoryboard.Begin(this);
            };

            myStackPanel.Children.Add(myRectangle);
            this.Content = myStackPanel;
        }
    }
}

Les sections suivantes décrivent TargetName les TargetProperty Propriétés et jointes plus en détail.

Ciblage des éléments d’infrastructure, des éléments de contenu d’infrastructure et des éléments Freezables

Dans la section précédente, il était mentionné que, pour qu’une animation trouve sa cible, elle devait connaître la propriété et le nom de la cible à animer. La spécification de la propriété à animer est directe : il suffit de définir le TargetProperty nom de la propriété à animer. Vous spécifiez le nom de l’objet dont vous souhaitez animer la propriété en définissant la Storyboard.TargetName propriété sur l’animation.

Attention

Bien que vous puissiez utiliser la Target propriété pour effectuer une liaison directe à un objet en guise d’alternative à TargetName , il n’est pas sérialisable. Il n’y a aucune garantie que l' Target objet puisse être correctement référencé en XAML.

Pour que la TargetName propriété fonctionne, l’objet ciblé doit avoir un nom. L’attribution d’un nom à un FrameworkElement ou un FrameworkContentElement dans XAML est différente de l’attribution d’un nom à un Freezable objet.

Les éléments de l’infrastructure sont les classes qui héritent de la FrameworkElement classe. Les exemples d’éléments d’infrastructure incluent Window , DockPanel , Button et Rectangle . Essentiellement, tous les contrôles, panneaux et fenêtres sont des éléments. Les éléments de contenu de l’infrastructure sont les classes qui héritent de la FrameworkContentElement classe. Les exemples d’éléments de contenu de Framework incluent FlowDocument et Paragraph . Si vous ne savez pas si un type est un élément d’infrastructure ou un élément de contenu d’infrastructure, vérifiez s’il possède une propriété Nom. Si c’est le cas, il s’agit probablement d’un élément d’infrastructure ou d’un élément de contenu d’infrastructure. Pour vous en assurer, vérifiez la section Inheritance Hierarchy (Hiérarchie d’héritage) de sa page de type.

Pour activer le ciblage d’un élément d’infrastructure ou d’un élément de contenu d’infrastructure dans XAML , vous devez définir sa Name propriété. Dans le code, vous devez également utiliser la RegisterName méthode pour enregistrer le nom de l’élément avec l’élément pour lequel vous avez créé un NameScope .

L’exemple suivant, extrait de l’exemple précédent, assigne le nom MyRectangle a Rectangle , un type FrameworkElement .

<Rectangle Name="MyRectangle"
  Width="100"
  Height="100">
Rectangle myRectangle = new Rectangle();
myRectangle.Name = "MyRectangle";

// Create a name scope for the page.
NameScope.SetNameScope(this, new NameScope());

this.RegisterName(myRectangle.Name, myRectangle);

Une fois qu’un nom a été assigné, vous pouvez animer une propriété de cet élément.

<DoubleAnimation 
  Storyboard.TargetName="MyRectangle"
  Storyboard.TargetProperty="Width"
  From="100" To="200" Duration="0:0:1" />
Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
Storyboard.SetTargetProperty(myDoubleAnimation,
    new PropertyPath(Rectangle.WidthProperty));

Freezable les types sont les classes qui héritent de la Freezable classe. Exemples de Freezable include SolidColorBrush , RotateTransform et GradientStop .

Pour activer le ciblage d’un Freezable par une animation dans XAML , vous utilisez la directive x :Name pour lui assigner un nom. Dans le code, vous utilisez la RegisterName méthode pour enregistrer son nom avec l’élément pour lequel vous avez créé un NameScope .

L’exemple suivant affecte un nom à un Freezable objet.

<SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
SolidColorBrush mySolidColorBrush = new SolidColorBrush(Colors.Blue);
this.RegisterName("MySolidColorBrush", mySolidColorBrush);

L’objet peut ensuite être ciblé par une animation.

<ColorAnimation 
  Storyboard.TargetName="MySolidColorBrush"
  Storyboard.TargetProperty="Color"
  From="Blue" To="Red" Duration="0:0:1" />  
Storyboard.SetTargetName(myColorAnimation, "MySolidColorBrush");
Storyboard.SetTargetProperty(myColorAnimation,
    new PropertyPath(SolidColorBrush.ColorProperty));

Storyboard les objets utilisent des portées de nom pour résoudre la TargetName propriété. Pour plus d’informations sur les portées de nom WPF, consultez Portées de nom XAML WPF. Si la TargetName propriété est omise, l’animation cible l’élément sur lequel elle est définie, ou, dans le cas des styles, l’élément stylisé.

Parfois, un nom ne peut pas être assigné à un Freezable objet. Par exemple, si un Freezable est déclaré en tant que ressource ou utilisé pour définir une valeur de propriété dans un style, il ne peut pas recevoir un nom. Comme il n’a pas de nom, il ne peut pas être ciblé directement, mais peut l’être indirectement. Les sections suivantes décrivent comment utiliser le ciblage indirect.

Ciblage indirect

Il peut arriver qu’un Freezable ne puisse pas être ciblé directement par une animation, par exemple lorsque le Freezable est déclaré en tant que ressource ou utilisé pour définir une valeur de propriété dans un style. Dans ce cas, même si vous ne pouvez pas le cibler directement, vous pouvez toujours animer l' Freezable objet. Au lieu de définir la TargetName propriété avec le nom du Freezable , vous lui donnez le nom de l’élément auquel le Freezable « appartient ». Par exemple, un SolidColorBrush utilisé pour définir le Fill d’un élément Rectangle appartient à ce rectangle. Pour animer le pinceau, vous devez définir les éléments de l’animation TargetProperty avec une chaîne de propriétés qui commence à la propriété de l’élément de l’infrastructure ou de l’élément de contenu de l’infrastructure que le Freezable a utilisé pour définir et se termine avec la Freezable propriété à animer.

<ColorAnimation 
  Storyboard.TargetName="Rectangle01"
  Storyboard.TargetProperty="Fill.Color"
  From="Blue" To="AliceBlue" Duration="0:0:1" />
DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath);

Notez que, si le Freezable est figé, un clone est créé et ce clone est animé. Dans ce cas, la propriété de l’objet d’origine HasAnimatedProperties continue à retourner false , car l’objet d’origine n’est pas réellement animé. Pour plus d’informations sur le clonage, consultez vue d’ensemble des objets Freezable.

Notez également que, lorsque vous utilisez le ciblage de propriété indirect, il est possible de cibler des objets qui n’existent pas. Par exemple, vous pouvez supposer que le Background d’un bouton particulier a été défini avec un SolidColorBrush et essayer d’animer sa couleur, alors qu’en fait un LinearGradientBrush a été utilisé pour définir l’arrière-plan du bouton. Dans ce cas, aucune exception n’est levée. l’animation ne peut pas avoir d’effet visible, car ne réagit LinearGradientBrush pas aux modifications apportées à la Color propriété.

Les sections suivantes décrivent plus en détail la syntaxe de ciblage de propriété indirect.

Ciblage indirect d’une propriété d’un élément Freezable en XAML

Pour cibler une propriété d’un Freezable dans XAML , utilisez la syntaxe suivante.

ElementPropertyName . FreezablePropertyName

Where

  • ElementPropertyName est la propriété du FrameworkElement qui Freezable est utilisé pour définir, et

  • FreezablePropertyName est la propriété du Freezable à animer.

Le code suivant montre comment animer le Color d’un SolidColorBrush utilisé pour définir le Fill d’un élément Rectangle.

<Rectangle
  Name="Rectangle01"
  Height="100"
  Width="100"
  Fill="{StaticResource MySolidColorBrushResource}">
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.MouseEnter">
      <BeginStoryboard>
        <Storyboard>
          <ColorAnimation 
            Storyboard.TargetName="Rectangle01"
            Storyboard.TargetProperty="Fill.Color"
            From="Blue" To="AliceBlue" Duration="0:0:1" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>

Vous devez parfois cibler un élément Freezable contenu dans une collection ou un tableau.

Pour cibler un élément Freezable contenu dans une collection, vous utilisez la syntaxe de chemin d’accès suivante.

ElementPropertyName .Children[ CollectionIndex ]. FreezablePropertyName

CollectionIndex est l’index de l’objet dans son tableau ou sa collection.

Par exemple, supposons qu’un rectangle a une TransformGroup ressource appliquée à sa RenderTransform propriété et que vous souhaitez animer l’une des transformations qu’il contient.

<TransformGroup x:Key="MyTransformGroupResource"
  x:Shared="False">
  <ScaleTransform />
  <RotateTransform />
</TransformGroup>

Le code suivant montre comment animer la Angle propriété de l' RotateTransform exemple indiqué dans l’exemple précédent.

<Rectangle
  Name="Rectangle02"
  Height="100"
  Width="100"
  Fill="Blue"
  RenderTransform="{StaticResource MyTransformGroupResource}">
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.MouseEnter">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation 
            Storyboard.TargetName="Rectangle02"
            Storyboard.TargetProperty="RenderTransform.Children[1].Angle"
            From="0" To="360" Duration="0:0:1" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>  

Ciblage indirect d’une propriété d’un élément Freezable dans le code

Dans le code, vous créez un PropertyPath objet. Lorsque vous créez le PropertyPath , vous spécifiez un Path et un PathParameters .

Pour créer PathParameters , vous créez un tableau de type DependencyProperty qui contient une liste de champs d’identificateur de propriété de dépendance. Le premier champ d’identificateur est pour la propriété du FrameworkElement ou FrameworkContentElement que le Freezable est utilisé pour définir. Le champ d’identificateur suivant représente la propriété du Freezable à cibler. Considérez-le comme une chaîne de propriétés qui connecte Freezable à l' FrameworkElement objet.

Voici un exemple de chaîne de propriété de dépendance qui cible le Color d’un SolidColorBrush utilisé pour définir le Fill d’un élément Rectangle.

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};

Vous devez également spécifier un Path . Un Path est un String qui indique Path à comment interpréter son PathParameters . Il utilise la syntaxe suivante.

( OwnerPropertyArrayIndex ).( FreezablePropertyArrayIndex )

Where

  • OwnerPropertyArrayIndex est l’index du DependencyProperty tableau qui contient l’identificateur de la propriété de l' FrameworkElement objet que le Freezable est utilisé pour définir, et

  • FreezablePropertyArrayIndex est l’index du DependencyProperty tableau qui contient l’identificateur de la propriété à cibler.

L’exemple suivant montre le Path qui s’accompagnerait du PathParameters défini dans l’exemple précédent.

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";

L’exemple suivant combine le code des exemples précédents pour animer le Color d’un SolidColorBrush utilisé pour définir le Fill d’un élément Rectangle.


// Create a name scope for the page.
NameScope.SetNameScope(this, new NameScope());

Rectangle rectangle01 = new Rectangle();
rectangle01.Name = "Rectangle01";
this.RegisterName(rectangle01.Name, rectangle01);
rectangle01.Width = 100;
rectangle01.Height = 100;
rectangle01.Fill =
    (SolidColorBrush)this.Resources["MySolidColorBrushResource"];

ColorAnimation myColorAnimation = new ColorAnimation();
myColorAnimation.From = Colors.Blue;
myColorAnimation.To = Colors.AliceBlue;
myColorAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTargetName(myColorAnimation, rectangle01.Name);

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath);

Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(myColorAnimation);
BeginStoryboard myBeginStoryboard = new BeginStoryboard();
myBeginStoryboard.Storyboard = myStoryboard;
EventTrigger myMouseEnterTrigger = new EventTrigger();
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent;
myMouseEnterTrigger.Actions.Add(myBeginStoryboard);
rectangle01.Triggers.Add(myMouseEnterTrigger);

Vous devez parfois cibler un élément Freezable contenu dans une collection ou un tableau. Par exemple, supposons qu’un rectangle a une TransformGroup ressource appliquée à sa RenderTransform propriété et que vous souhaitez animer l’une des transformations qu’il contient.

<TransformGroup x:Key="MyTransformGroupResource"
  x:Shared="False">
  <ScaleTransform />
  <RotateTransform />
</TransformGroup>  

Pour cibler un Freezable contenu dans une collection, vous utilisez la syntaxe de chemin d’accès suivante.

( OwnerPropertyArrayIndex ).( CollectionChildrenPropertyArrayIndex ) [ CollectionIndex ].( FreezablePropertyArrayIndex )

CollectionIndex est l’index de l’objet dans son tableau ou sa collection.

Pour cibler la Angle propriété du RotateTransform , la deuxième transformation dans le TransformGroup , utilisez les éléments suivants Path et PathParameters .

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {
            Rectangle.RenderTransformProperty,
            TransformGroup.ChildrenProperty,
            RotateTransform.AngleProperty
        };
string thePath = "(0).(1)[1].(2)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath);

L’exemple suivant montre le code complet pour animer le Angle d’un RotateTransform contenu dans un TransformGroup .

Rectangle rectangle02 = new Rectangle();
rectangle02.Name = "Rectangle02";
this.RegisterName(rectangle02.Name, rectangle02);
rectangle02.Width = 100;
rectangle02.Height = 100;
rectangle02.Fill = Brushes.Blue;
rectangle02.RenderTransform =
    (TransformGroup)this.Resources["MyTransformGroupResource"];

DoubleAnimation myDoubleAnimation = new DoubleAnimation();
myDoubleAnimation.From = 0;
myDoubleAnimation.To = 360;
myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTargetName(myDoubleAnimation, rectangle02.Name);

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {
            Rectangle.RenderTransformProperty,
            TransformGroup.ChildrenProperty,
            RotateTransform.AngleProperty
        };
string thePath = "(0).(1)[1].(2)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath);

Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(myDoubleAnimation);
BeginStoryboard myBeginStoryboard = new BeginStoryboard();
myBeginStoryboard.Storyboard = myStoryboard;
EventTrigger myMouseEnterTrigger = new EventTrigger();
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent;
myMouseEnterTrigger.Actions.Add(myBeginStoryboard);
rectangle02.Triggers.Add(myMouseEnterTrigger);

Ciblage indirect avec un élément Freezable comme point de départ

Les sections précédentes décrivaient comment cibler indirectement un Freezable en commençant par un FrameworkElement ou FrameworkContentElement et en créant une chaîne de propriétés à une Freezable sous-propriété. Vous pouvez également utiliser un Freezable comme point de départ et cibler indirectement l’une de ses Freezable sous-propriétés. Une restriction supplémentaire s’applique lors de l’utilisation Freezable d’un comme point de départ pour le ciblage indirect : la Freezable sous-propriété de départ et toutes les Freezable entre et la sous-propriété indirectement ciblée ne doivent pas être figées.

Contrôle interactif d’une table de montage séquentiel en XAML

Pour démarrer une table de montage séquentiel dans langage XAML (eXtensible Application Markup Language) , vous utilisez une BeginStoryboard action de déclencheur. BeginStoryboard distribue les animations aux objets et propriétés qu’elles animent, et démarre le Storyboard. (Pour plus d’informations sur ce processus, consultez vue d’ensemble du système d’animation et de minutage.) Si vous donnez BeginStoryboard un nom à un nom en spécifiant sa Name propriété, vous en faites une table de montage séquentiel contrôlable. Vous pouvez ensuite contrôler interactivement la table de montage séquentiel après son démarrage. Vous trouverez ci-dessous une liste d’actions de table de montage séquentiel contrôlable à utiliser avec des déclencheurs d’événements pour contrôler une table de montage séquentiel.

Dans l’exemple suivant, les actions de table de montage séquentiel contrôlable servent à contrôler interactivement une table de montage séquentiel.

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.SDK.Animation.ControllableStoryboardExample"
  WindowTitle="Fading Rectangle Example">
  <StackPanel Margin="10">

    <Rectangle
      Name="MyRectangle"
      Width="100" 
      Height="100"
      Fill="Blue">
    </Rectangle>

    <Button Name="BeginButton">Begin</Button>
    <Button Name="PauseButton">Pause</Button>
    <Button Name="ResumeButton">Resume</Button>
    <Button Name="SkipToFillButton">Skip To Fill</Button>
    <Button Name="StopButton">Stop</Button>

    <StackPanel.Triggers>
      <EventTrigger RoutedEvent="Button.Click" SourceName="BeginButton">
        <BeginStoryboard Name="MyBeginStoryboard">
          <Storyboard>
            <DoubleAnimation
              Storyboard.TargetName="MyRectangle" 
              Storyboard.TargetProperty="(Rectangle.Opacity)"
              From="1.0" To="0.0" Duration="0:0:5" />
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="PauseButton">
        <PauseStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="ResumeButton">
        <ResumeStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="SkipToFillButton">
        <SkipStoryboardToFill BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="StopButton">
        <StopStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
    </StackPanel.Triggers>
  </StackPanel>
</Page>

Contrôle interactif d’une table de montage séquentiel avec du code

Les exemples précédents ont montré comment animer à l’aide d’actions de déclencheur. Dans le code, vous pouvez également contrôler une table de montage séquentiel à l’aide de méthodes interactives de la Storyboard classe. Pour qu’un Storyboard soit rendu interactif dans le code, vous devez utiliser la surcharge appropriée de la méthode de la table de montage séquentiel Begin et spécifier true pour le rendre contrôlable. Pour plus d'informations, consultez la page Begin(FrameworkElement, Boolean).

La liste suivante présente les méthodes qui peuvent être utilisées pour manipuler un Storyboard après son démarrage :

L’avantage de l’utilisation de ces méthodes est que vous n’avez pas besoin de créer Trigger TriggerAction des objets ou ; vous avez simplement besoin d’une référence au contrôlable Storyboard que vous souhaitez manipuler.

Notes

Toutes les actions interactives effectuées sur un Clock et, par conséquent, sur un Storyboard se produisent sur le cycle suivant du moteur de minutage qui se produira peu de temps avant le rendu suivant. Par exemple, si vous utilisez la Seek méthode pour accéder à un autre point d’une animation, la valeur de la propriété ne change pas instantanément, plutôt que la valeur change sur le cycle suivant du moteur de minutage.

L’exemple suivant montre comment appliquer et contrôler des animations à l’aide des méthodes interactives de la Storyboard classe.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace SDKSample
{

    public class ControllableStoryboardExample : Page
    {
        private Storyboard myStoryboard;

        public ControllableStoryboardExample()
        {

            // Create a name scope for the page.

            NameScope.SetNameScope(this, new NameScope());

            this.WindowTitle = "Controllable Storyboard Example";
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(10);

            // Create a rectangle.
            Rectangle myRectangle = new Rectangle();
            myRectangle.Name = "myRectangle";

            // Assign the rectangle a name by
            // registering it with the page, so that
            // it can be targeted by storyboard
            // animations.
            this.RegisterName(myRectangle.Name, myRectangle);
            myRectangle.Width = 100;
            myRectangle.Height = 100;
            myRectangle.Fill = Brushes.Blue;
            myStackPanel.Children.Add(myRectangle);

            //
            // Create an animation and a storyboard to animate the
            // rectangle.
            //
            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 1.0;
            myDoubleAnimation.To = 0.0;
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(5000));
            myDoubleAnimation.AutoReverse = true;

            // Create the storyboard.
            myStoryboard = new Storyboard();
            myStoryboard.Children.Add(myDoubleAnimation);
            Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
            Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Rectangle.OpacityProperty));

            //
            // Create some buttons to control the storyboard
            // and a panel to contain them.
            //
            StackPanel buttonPanel = new StackPanel();
            buttonPanel.Orientation = Orientation.Horizontal;
            Button beginButton = new Button();
            beginButton.Content = "Begin";
            beginButton.Click += new RoutedEventHandler(beginButton_Clicked);
            buttonPanel.Children.Add(beginButton);
            Button pauseButton = new Button();
            pauseButton.Content = "Pause";
            pauseButton.Click += new RoutedEventHandler(pauseButton_Clicked);
            buttonPanel.Children.Add(pauseButton);
            Button resumeButton = new Button();
            resumeButton.Content = "Resume";
            resumeButton.Click += new RoutedEventHandler(resumeButton_Clicked);
            buttonPanel.Children.Add(resumeButton);
            Button skipToFillButton = new Button();
            skipToFillButton.Content = "Skip to Fill";
            skipToFillButton.Click += new RoutedEventHandler(skipToFillButton_Clicked);
            buttonPanel.Children.Add(skipToFillButton);
            Button setSpeedRatioButton = new Button();
            setSpeedRatioButton.Content = "Triple Speed";
            setSpeedRatioButton.Click += new RoutedEventHandler(setSpeedRatioButton_Clicked);
            buttonPanel.Children.Add(setSpeedRatioButton);
            Button stopButton = new Button();
            stopButton.Content = "Stop";
            stopButton.Click += new RoutedEventHandler(stopButton_Clicked);
            buttonPanel.Children.Add(stopButton);
            myStackPanel.Children.Add(buttonPanel);
            this.Content = myStackPanel;
        }

        // Begins the storyboard.
        private void beginButton_Clicked(object sender, RoutedEventArgs args)
        {
            // Specifying "true" as the second Begin parameter
            // makes this storyboard controllable.
            myStoryboard.Begin(this, true);
        }

        // Pauses the storyboard.
        private void pauseButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Pause(this);
        }

        // Resumes the storyboard.
        private void resumeButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Resume(this);
        }

        // Advances the storyboard to its fill period.
        private void skipToFillButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.SkipToFill(this);
        }

        // Updates the storyboard's speed.
        private void setSpeedRatioButton_Clicked(object sender, RoutedEventArgs args)
        {
            // Makes the storyboard progress three times as fast as normal.
            myStoryboard.SetSpeedRatio(this, 3);
        }

        // Stops the storyboard.
        private void stopButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Stop(this);
        }
    }
}

Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Shapes
Imports System.Windows.Media
Imports System.Windows.Media.Animation

Namespace SDKSample

    Public Class ControllableStoryboardExample
        Inherits Page
        Private myStoryboard As Storyboard

        Public Sub New()

            ' Create a name scope for the page.

            NameScope.SetNameScope(Me, New NameScope())

            Me.WindowTitle = "Controllable Storyboard Example"
            Dim myStackPanel As New StackPanel()
            myStackPanel.Margin = New Thickness(10)

            ' Create a rectangle.
            Dim myRectangle As New Rectangle()
            myRectangle.Name = "myRectangle"

            ' Assign the rectangle a name by 
            ' registering it with the page, so that
            ' it can be targeted by storyboard
            ' animations.
            Me.RegisterName(myRectangle.Name, myRectangle)
            myRectangle.Width = 100
            myRectangle.Height = 100
            myRectangle.Fill = Brushes.Blue
            myStackPanel.Children.Add(myRectangle)

            '
            ' Create an animation and a storyboard to animate the
            ' rectangle.
            '
            Dim myDoubleAnimation As New DoubleAnimation()
            myDoubleAnimation.From = 1.0
            myDoubleAnimation.To = 0.0
            myDoubleAnimation.Duration = New Duration(TimeSpan.FromMilliseconds(5000))
            myDoubleAnimation.AutoReverse = True

            ' Create the storyboard.
            myStoryboard = New Storyboard()
            myStoryboard.Children.Add(myDoubleAnimation)
            Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name)
            Storyboard.SetTargetProperty(myDoubleAnimation, New PropertyPath(Rectangle.OpacityProperty))

            '
            ' Create some buttons to control the storyboard
            ' and a panel to contain them.
            '
            Dim buttonPanel As New StackPanel()
            buttonPanel.Orientation = Orientation.Horizontal
            Dim beginButton As New Button()
            beginButton.Content = "Begin"
            AddHandler beginButton.Click, AddressOf beginButton_Clicked
            buttonPanel.Children.Add(beginButton)
            Dim pauseButton As New Button()
            pauseButton.Content = "Pause"
            AddHandler pauseButton.Click, AddressOf pauseButton_Clicked
            buttonPanel.Children.Add(pauseButton)
            Dim resumeButton As New Button()
            resumeButton.Content = "Resume"
            AddHandler resumeButton.Click, AddressOf resumeButton_Clicked
            buttonPanel.Children.Add(resumeButton)
            Dim skipToFillButton As New Button()
            skipToFillButton.Content = "Skip to Fill"
            AddHandler skipToFillButton.Click, AddressOf skipToFillButton_Clicked
            buttonPanel.Children.Add(skipToFillButton)
            Dim setSpeedRatioButton As New Button()
            setSpeedRatioButton.Content = "Triple Speed"
            AddHandler setSpeedRatioButton.Click, AddressOf setSpeedRatioButton_Clicked
            buttonPanel.Children.Add(setSpeedRatioButton)
            Dim stopButton As New Button()
            stopButton.Content = "Stop"
            AddHandler stopButton.Click, AddressOf stopButton_Clicked
            buttonPanel.Children.Add(stopButton)
            myStackPanel.Children.Add(buttonPanel)
            Me.Content = myStackPanel


        End Sub

        ' Begins the storyboard.
        Private Sub beginButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            ' Specifying "true" as the second Begin parameter
            ' makes this storyboard controllable.
            myStoryboard.Begin(Me, True)

        End Sub

        ' Pauses the storyboard.
        Private Sub pauseButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Pause(Me)

        End Sub

        ' Resumes the storyboard.
        Private Sub resumeButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Resume(Me)

        End Sub

        ' Advances the storyboard to its fill period.
        Private Sub skipToFillButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.SkipToFill(Me)

        End Sub

        ' Updates the storyboard's speed.
        Private Sub setSpeedRatioButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            ' Makes the storyboard progress three times as fast as normal.
            myStoryboard.SetSpeedRatio(Me, 3)

        End Sub

        ' Stops the storyboard.
        Private Sub stopButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Stop(Me)

        End Sub

    End Class

End Namespace

Animer dans un style

Vous pouvez utiliser Storyboard des objets pour définir des animations dans un Style . L’animation avec un Storyboard dans un Style est semblable à l’utilisation d’un Storyboard autre emplacement, avec les trois exceptions suivantes :

  • Vous ne spécifiez pas un TargetName ; le Storyboard cible toujours l’élément auquel le Style est appliqué. Pour cibler Freezable des objets, vous devez utiliser le ciblage indirect. Pour plus d’informations sur le ciblage indirect, consultez la section ciblage indirect .

  • Vous ne pouvez pas spécifier un SourceName pour un EventTrigger ou un Trigger .

  • Vous ne pouvez pas utiliser des références de ressources dynamiques ou des expressions de liaison de données pour définir Storyboard ou animations des valeurs de propriété. Cela est dû au fait que tout ce qui se trouve dans un Style doit être thread-safe et que le système de minutage doit les Freeze Storyboard objets pour les rendre thread-safe. Un Storyboard ne peut pas être figé s’il ou ses chronologies enfants contiennent des références de ressources dynamiques ou des expressions de liaison de données. Pour plus d’informations sur le gel et Freezable d’autres fonctionnalités, consultez la vue d’ensemble des objets Freezable.

  • Dans XAML , vous ne pouvez pas déclarer de gestionnaires d’événements pour les Storyboard événements d’animation ou.

Pour obtenir un exemple qui montre comment définir une table de montage séquentiel dans un style, consultez l’exemple animer dans un style .

Effectuer une animation dans un ControlTemplate

Vous pouvez utiliser Storyboard des objets pour définir des animations dans un ControlTemplate . L’animation avec un Storyboard dans un ControlTemplate est semblable à l’utilisation d’un Storyboard autre emplacement, avec les deux exceptions suivantes :

  • TargetNamePeut uniquement faire référence aux objets enfants de ControlTemplate . Si TargetName n’est pas spécifié, l’animation cible l’élément auquel ControlTemplate est appliqué.

  • SourceNamePour un EventTrigger ou un Trigger peut uniquement faire référence aux objets enfants de ControlTemplate .

  • Vous ne pouvez pas utiliser des références de ressources dynamiques ou des expressions de liaison de données pour définir Storyboard ou animations des valeurs de propriété. Cela est dû au fait que tout ce qui se trouve dans un ControlTemplate doit être thread-safe et que le système de minutage doit les Freeze Storyboard objets pour les rendre thread-safe. Un Storyboard ne peut pas être figé s’il ou ses chronologies enfants contiennent des références de ressources dynamiques ou des expressions de liaison de données. Pour plus d’informations sur le gel et Freezable d’autres fonctionnalités, consultez la vue d’ensemble des objets Freezable.

  • Dans XAML , vous ne pouvez pas déclarer de gestionnaires d’événements pour les Storyboard événements d’animation ou.

Pour obtenir un exemple illustrant comment définir une table de montage séquentiel dans un ControlTemplate , consultez l’exemple animation dans un ControlTemplate .

Animer en cas de modification d’une valeur de propriété

Dans les styles et les modèles de contrôle, vous pouvez utiliser des objets Trigger pour démarrer une table de montage séquentiel en cas de modification d’une propriété. Pour obtenir des exemples, consultez déclencher une animation quand une valeur de propriété change et animer dans un ControlTemplate.

Les animations appliquées par les Trigger objets de propriété se comportent de manière plus complexe que les EventTrigger animations ou les animations démarrées à l’aide de Storyboard méthodes. Ils « sont remis » avec les animations définies par d’autres Trigger objets, mais composent avec les EventTrigger animations déclenchées par la méthode et.

Voir aussi