Vue d'ensemble des tables de montage séquentiel
Mise à jour : novembre 2007
Cette rubrique indique comment utiliser des objets Storyboard pour organiser et appliquer des animations. Elle décrit comment manipuler des objets Storyboard interactivement et décrit la syntaxe de ciblage de propriété indirecte.
Composants requis
Pour comprendre cette rubrique, vous devez être familiarisé avec les différents types d'animation et leurs fonctionnalités de base. Pour une présentation des fonctionnalités d'animation, consultez Vue d'ensemble de l'animation. Vous devez également savoir comment utiliser des propriétés attachées. Pour plus d'informations sur le fonctionnement des propriétés attachées, consultez Vue d'ensemble des propriétés attachées.
Qu'est-ce qu'une table de montage séquentiel ?
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 classe TimelineGroup et incluent ParallelTimeline et Storyboard.
Un Storyboard est un type de chronologie de conteneur qui fournit des informations de ciblage pour les animations qu'il contient. Une table de montage séquentiel peut contenir tout type de Timeline, y compris d'autres chronologies de conteneur et animations. Les objets Storyboard vous permettent de combiner des chronologies qui affectent divers objets et propriétés dans une arborescence chronologique unique, simplifiant l'organisation et le contrôle des comportements d'horloge complexes. Par exemple, supposez que vous souhaitiez un bouton qui fasse ces trois choses.
Grandit et change de couleur lorsque l'utilisateur sélectionne le bouton.
Réduit et reprend sa taille d'origine en cas de clic.
Réduit et s'atténue à 50 pour cent d'opacité lorsqu'il est désactivé.
Dans ce cas, vous avez plusieurs jeux d'animations qui s'appliquent au même objet, que vous souhaitez jouer à des moments différents, en fonction de l'état du bouton. Les objets Storyboard vous permettent d'organiser des 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 permet d'animer une classe, consultez Vue d'ensemble de l'animation). Toutefois, du fait que les tables de montage séquentiel sont une fonctionnalité de niveau infrastructure, l'objet doit appartenir au NameScope d'un FrameworkElement ou d'un FrameworkContentElement.
Par exemple, vous pourriez utiliser un Storyboard pour effectuer les opérations suivantes :
Animer un SolidColorBrush (élément ne faisant pas partie de l'infrastructure) qui peint l'arrière-plan d'un bouton (un type de FrameworkElement),
Animer un SolidColorBrush (élément ne faisant pas partie de l'infrastructure) qui peint le remplissage d'un GeometryDrawing (élément ne faisant pas partie de l'infrastructure) affiché à l'aide d'un Image (FrameworkElement).
Dans le code, animer un SolidColorBrush déclaré par une classe qui contient également un FrameworkElement, si le SolidColorBrush a enregistré son nom avec ce FrameworkElement.
Toutefois, vous n'avez pas pu utiliser de Storyboard pour animer un SolidColorBrush qui n'a pas enregistré son nom avec un FrameworkElement ou FrameworkContentElement, ou qui n'a pas été utilisé pour définir une propriété d'un FrameworkElement ou 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 comme chronologies enfants du Storyboard. La classe Storyboard fournit les propriétés attachées Storyboard.TargetName et Storyboard.TargetProperty. Vous définissez ces propriétés sur une animation pour spécifier son objet et propriété cibles.
Pour appliquer des animations à leurs cibles, vous commencez le Storyboard à l'aide d'une action de déclencheur ou d'une méthode. En XAML, vous utilisez un objet BeginStoryboard avec un EventTrigger, Trigger, ou DataTrigger. Dans le code, vous pouvez également utiliser la méthode Begin.
Le tableau suivant indique les différents endroits où chaque technique de démarrage de Storyboard 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 d'application d'une animation ou d'une table de montage séquentiel directement aux instances d'un objet, plutôt que dans un style, modèle de contrôle ou modèle de données.
La table de montage séquentiel commence à être utilisée… |
Par instance |
Style |
Modèle de contrôle |
Modèle de données |
Exemple |
---|---|---|---|---|---|
BeginStoryboard et un EventTrigger |
Oui |
Oui |
Oui |
Oui |
Comment : animer une propriété à l'aide d'une table de montage séquentiel |
BeginStoryboard et une propriété Trigger |
Non |
Oui |
Oui |
Oui |
Comment : déclencher une animation en cas de modification d'une valeur de propriété |
BeginStoryboard et un DataTrigger |
Non |
Oui |
Oui |
Oui |
Comment : déclencher une animation en cas de modification de données |
Méthode Begin |
Oui |
Non |
Non |
Non |
Comment : 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 élément Rectangle et le Color d'un SolidColorBrush utilisé pour peindre ce Rectangle.
<!-- This example shows how to animate with a storyboard.-->
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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 plus en détail les propriétés attachées TargetName et TargetProperty.
Ciblage d'éléments d'infrastructure, éléments du contenu de l'infrastructure et Freezables
La section précédente a mentionné que pour qu'une animation trouve sa cible, elle doit connaître le nom de la cible et la propriété à animer. La spécification de la propriété à animer est très simple : il suffit de définir Storyboard.TargetProperty avec le nom de la propriété à animer. Vous indiquez le nom de l'objet dont vous souhaitez animer la propriété en définissant la propriété Storyboard.TargetName sur l'animation.
Pour que la propriété TargetName fonctionne, l'objet ciblé doit avoir un nom. L'affectation d'un nom à un FrameworkElement ou un FrameworkContentElement en XAML diffère de l'affectation d'un nom à un objet Freezable.
Les éléments d'infrastructure sont les classes qui héritent de la classe FrameworkElement. Window, DockPanel, Button, et Rectangle sont des exemples d'éléments d'infrastructure. En général, toutes les fenêtres, volets et contrôles sont des éléments. Les éléments du contenu de l'infrastructure sont les classes qui héritent de la classe FrameworkContentElement. FlowDocument et Paragraph sont des exemples d'éléments du contenu de l'infrastructure. Si vous n'êtes pas sûr si un type est un élément d'infrastructure ou un élément du contenu de l'infrastructure, vérifiez s'il dispose d'une propriété Name. Si c'est le cas, il s'agit probablement d'un élément d'infrastructure ou d'un élément du contenu de l'infrastructure. Pour être sûr, vérifiez la section Hiérarchied'héritage de sa page type.
Pour activer le ciblage d'un élément d'infrastructure ou d'un élément du contenu de l'infrastructure en XAML, définissez sa propriété Name. Dans le code, vous devez également utiliser la méthode RegisterName pour enregistrer le nom de l'élément avec l'élément pour lequel vous avez créé un NameScope.
L'exemple suivant, pris de l'exemple précédent, attribue le nom MyRectangle à un Rectangle, un type de 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 que l'élément est nommé, 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));
Les types Freezable sont les classes qui héritent de la classe Freezable. SolidColorBrush, RotateTransform, et GradientStop sont des exemples de Freezable.
Pour activer le ciblage d'un Freezable par une animation en XAML, vous utilisez le x:Name, attribut pour lui attribuer un nom. Dans le code, vous utilisez la méthode RegisterName pour enregistrer son nom avec l'élément pour lequel vous avez créé un NameScope.
L'exemple suivant attribue un nom à un objet Freezable.
<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));
Les objets Storyboard utilisent des portées de nom pour résoudre la propriété TargetName. Pour plus d'informations sur les portées de nom WPF, consultez Portées de nom WPF. Si la propriété TargetName est omise, l'animation cible l'élément sur lequel elle est définie, ou, dans le cas de styles, l'élément auquel est appliqué un style.
Il arrive parfois qu'un nom ne puisse pas être attribué à un objet Freezable. Par exemple, si un Freezable est déclaré comme une ressource ou utilisé pour définir une valeur de propriété dans un style, aucun nom ne peut lui être donné. Du fait qu'il n'a pas de nom, il ne peut pas être ciblé directement, mais peut être ciblé indirectement. Les sections suivantes décrivent comment utiliser le ciblage indirect.
Ciblage indirect
Il arrive qu'un Freezable ne puisse pas être ciblé directement par une animation, comme quand le Freezable est déclaré comme une ressource ou utilisé définir une valeur de propriété dans un style. Dans ces cas, bien que vous ne puissiez pas le cibler directement, vous pouvez encore animer l'objet Freezable. Au lieu de définir la propriété TargetName avec le nom du Freezable, vous lui donnez le nom de l'élément auquel "appartient" le Freezable. Par exemple, un SolidColorBrush utilisé pour définir le Fill d'un élément rectangle appartient à ce rectangle. Pour animer le pinceau, vous devrez définir la propriété TargetProperty de l'animation avec une chaîne de propriétés qui démarre à la propriété de l'élément d'infrastructure ou de l'élément du contenu de l'infrastructure le Freezable utilisé pour la définition et se termine avec la propriété Freezable à 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 sera créé, et que ce clone sera animé. Lorsque cela se produit, la propriété HasAnimatedProperties de l'objet d'origine continue à retourner false, car l'objet d'origine n'est pas animé réellement. Pour plus d'informations sur les clones, consultez Vue d'ensemble des objets Freezable.
Notez également que lors de l'utilisation du ciblage indirect de propriété, il est possible de cibler des objets qui n'existent pas. Par exemple, vous pouvez supposer que l'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 ces cas, aucune exception n'est renvoyée ; l'animation ne parvient pas à avoir un effet visible car LinearGradientBrush ne réagit pas aux modifications apportées à la propriété Color.
Les sections suivantes décrivent plus en détail la syntaxe de ciblage indirect de propriété.
Ciblage indirect d'une propriété d'un Freezable en XAML
Pour cibler une propriété d'un freezable en XAML, utilisez la syntaxe suivante.
ElementPropertyName.FreezablePropertyName |
Où
ElementPropertyName est la propriété de FrameworkElement que le Freezable utilise 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 freezable contenu dans une collection ou un tableau.
Pour cibler un freezable contenu dans une collection, vous utilisez la syntaxe Path suivante.
ElementPropertyName.Children[CollectionIndex].FreezablePropertyName |
Où CollectionIndex est l'index de l'objet dans son tableau ou sa collection.
Par exemple, supposez qu'un rectangle a une ressource TransformGroup appliquée à sa propriété RenderTransform, 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 indique comment animer la propriété Angle de la RotateTransform affichée 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 Freezable dans le code
Dans le code, vous créez un objet PropertyPath. Lorsque vous créez le PropertyPath, vous spécifiez un Path et des 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é de l'FrameworkElement ou FrameworkContentElement que le Freezable utilise 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 le Freezable à l'objet FrameworkElement.
Les éléments suivants sont un exemple d'une 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 une String qui explique au Path comment interpréter ses PathParameters. Il utilise la syntaxe suivante.
(OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex) |
Où
OwnerPropertyArrayIndex est l'index du tableau DependencyProperty qui contient l'identificateur de la propriété de l'objet FrameworkElement que le Freezable utilise pour définir, et
FreezablePropertyArrayIndex est l'index du tableau DependencyProperty qui contient l'identificateur de propriété à cibler.
L'exemple suivant montre le Path qui devrait accompagner les PathParameters définie 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 freezable contenu dans une collection ou un tableau. Par exemple, supposez qu'un rectangle a une ressource TransformGroup appliquée à sa propriété RenderTransform, 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 Path suivante.
(OwnerPropertyArrayIndex).(CollectionChildrenPropertyArrayIndex)[CollectionIndex].(FreezablePropertyArrayIndex) |
Où CollectionIndex est l'index de l'objet dans son tableau ou sa collection.
Pour cibler la propriété Angle de la deuxième RotateTransform transformation dans le TransformGroup, vous utiliseriez le Path suivant 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 affiche le code complet pour animer l'Angle d'une RotateTransform a contenue 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 Freezable comme point de départ
Les sections précédentes ont décrit comment cibler indirectement un Freezable en démarrant avec un FrameworkElement ou FrameworkContentElement et en créant une chaîne de propriété à une sous-propriété Freezable. Vous pouvez également utiliser un Freezable comme point de départ et cibler indirectement l'une de ses sous-propriétés Freezable. Une restriction supplémentaire s'applique lors de l'utilisation d'un Freezable comme point de départ pour le ciblage indirect : le Freezable initial et chaque Freezable entre lui et la sous-propriété indirectement ciblée ne doivent pas être figés.
Contrôle interactif d'une table de montage séquentiel en XAML
Pour démarrer une table de montage séquentiel en XAML (Extensible Application Markup Language), vous utilisez une action de déclenchement BeginStoryboard. BeginStoryboard distribue les animations aux objets et aux propriétés qu'ils animent, et démarre la table de montage séquentiel. (Pour plus de détails sur ce processus, consultez Vue d'ensemble de l'animation et du système de minutage). Si vous donnez un nom à BeginStoryboard en spécifiant sa propriété Name, 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. Les éléments suivants sont une liste d'actions de table de montage séquentiel vérifiables que vous utilisez avec les déclencheurs d'événements pour contrôler une table de montage séquentiel.
PauseStoryboard : suspend la table de montage séquentiel.
ResumeStoryboard : reprend une table de montage séquentiel suspendu.
SetStoryboardSpeedRatio : modifie la vitesse de la table de montage séquentiel.
SkipStoryboardToFill : fait avancer une table de montage séquentiel à la fin de sa période de remplissage, le cas échéant.
StopStoryboard : arrête la table de montage séquentiel.
RemoveStoryboard : supprime la table de montage séquentiel.
Dans l'exemple suivant, des actions de table de montage séquentiel contrôlables sont utilisées pour contrôler interactivement une table de montage séquentiel.
<Page
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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ôler interactivement une table de montage séquentiel en utilisant du code
Les exemples précédents ont indiqué comment animer l'utilisation d'actions de déclencheur. Dans le code, vous pouvez également contrôler une table de montage séquentiel à l'aide des méthodes interactives de la classe Storyboard. Pour qu'un Storyboard soit rendu interactif dans le code, vous devez utiliser la surcharge appropriée de la méthode Begin de la table de montage séquentiel et spécifier la valeur true pour qu'elle soit contrôlable. Pour plus d'informations, consultez la page Begin(FrameworkElement, Boolean).
La liste suivante affiche les méthodes qui peuvent être utilisées pour manipuler un Storyboard après son démarrage :
L'avantage d'utiliser ces méthodes est que vous n'avez pas besoin de créer d'objets Trigger ou TriggerAction ; vous avez juste besoin d'une référence au Storyboard contrôlable que vous souhaitez manipuler.
Remarque : toutes les actions interactives effectuées sur un Clock, et par conséquent également sur un Storyboard, se produiront sur le battement suivant du moteur de minutage, ce qui se produira peu avant le rendu suivant. Par exemple, si vous utilisez la méthode Seek pour accéder à un autre point dans une animation, la valeur de propriété ne change pas instantanément, mais plutôt sur le battement suivant du moteur de minutage.
L'exemple suivant indique comment appliquer et contrôler des animations à l'aide des méthodes interactives de la classe Storyboard.
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);
}
}
}
Animer dans un style
Vous pouvez utiliser des objets Storyboard pour définir des animations dans un Style. Animer avec un Storyboard dans un Style est semblable à l'utilisation d'un Storyboard ailleurs, avec les trois exceptions suivantes :
Vous ne spécifiez pas de TargetName ; le Storyboard cible toujours l'élément auquel est appliqué le Style. Pour cibler des objets Freezable, 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 de SourceName pour un EventTrigger ou un Trigger.
Vous ne pouvez pas utiliser de références à une ressource dynamique ou d'expressions de liaison de données pour définir Storyboard ou des valeurs de propriété d'animation. La raison est que tout ce qui se trouve à l'intérieur d'un Style doit être thread-safe, et que le système d'horloge doit Freezeles objets Storyboard pour les rendre thread-safe. Un Storyboard ne peut pas être figé si lui ou ses chronologies enfants contiennent des références à une ressource dynamique ou des expressions de liaison de données. Pour plus d'informations sur le blocage et d'autres fonctionnalités Freezable, consultez Vue d'ensemble des objets Freezable.
En XAML, vous ne pouvez pas déclarer de gestionnaires d'événements pour Storyboard ou les événements d'animation.
Pour obtenir un exemple qui indique comment définir une table de montage séquentiel dans un style, consultez l'exemple Comment : animer dans un style.
Animer dans un modèle de contrôle
Vous pouvez utiliser des objets Storyboard pour définir des animations dans un ControlTemplate. Animer avec un Storyboard dans un ControlTemplate est semblable à l'utilisation d'un Storyboard ailleurs, avec les deux exceptions suivantes :
Le TargetName peut faire référence uniquement aux objets enfants du ControlTemplate. Si TargetName n'est pas spécifié, l'animation cible l'élément auquel est appliqué le ControlTemplate.
Le SourceName pour un EventTrigger ou un Trigger peut faire référence uniquement aux objets enfants du ControlTemplate.
Vous ne pouvez pas utiliser de références à une ressource dynamique ou d'expressions de liaison de données pour définir Storyboard ou des valeurs de propriété d'animation. La raison est que tout ce qui se trouve à l'intérieur d'un ControlTemplate doit être thread-safe, et que le système d'horloge doit Freezeles objets Storyboard pour les rendre thread-safe. Un Storyboard ne peut pas être figé si lui ou ses chronologies enfants contiennent des références à une ressource dynamique ou des expressions de liaison de données. Pour plus d'informations sur le blocage et d'autres fonctionnalités Freezable, consultez Vue d'ensemble des objets Freezable.
En XAML, vous ne pouvez pas déclarer de gestionnaires d'événements pour Storyboard ou les événements d'animation.
Pour obtenir un exemple qui indique comment définir une table de montage séquentiel dans un ControlTemplate, consultez l'exemple Comment : effectuer une animation dans un ControlTemplate.
Animer lorsqu'une valeur de propriété est modifiée
Dans les styles et les modèles de contrôle, vous pouvez utiliser des objets déclencheurs pour démarrer une table de montage séquentiel lorsqu'une propriété change. Pour obtenir des exemples, consultez Comment : déclencher une animation en cas de modification d'une valeur de propriété et Comment : effectuer une animation dans un ControlTemplate.
Les animations appliquées par les objets de propriété Trigger se comportent d'une façon plus complexe que les animations EventTrigger ou les animations démarrées à l'aide des méthodes Storyboard. Elles "procèdent au transfert" avec les animations définies par d'autres objets Trigger, mais composent avec des EventTrigger et des animations déclenchées par méthode.