Vue d'ensemble des storyboards
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 jointes.
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. Un storyboard peut contenir n'importe quel type de Timeline, y compris les chronologies et animations d'un autre conteneur. Les objets Storyboard vous permettent de combiner les chronologies qui affectent divers objets et propriétés en une arborescence de chronologie unique, ce qui facilite l'organisation et le contrôle des comportements de minutage 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 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 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'un storyboard directement aux instances d'un objet, plutôt que dans un style, un modèle de contrôle ou un 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 |
|
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 |
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>
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Data
Imports System.Windows.Shapes
Imports System.Windows.Input
Namespace Microsoft.Samples.Animation
Public Class StoryboardsExample
Inherits Page
Public Sub New()
Me.WindowTitle = "Storyboards Example"
Dim myStackPanel As New StackPanel()
myStackPanel.Margin = New Thickness(20)
Dim myRectangle As New Rectangle()
myRectangle.Name = "MyRectangle"
' Create a name scope for the page.
NameScope.SetNameScope(Me, New NameScope())
Me.RegisterName(myRectangle.Name, myRectangle)
myRectangle.Width = 100
myRectangle.Height = 100
Dim mySolidColorBrush As New SolidColorBrush(Colors.Blue)
Me.RegisterName("MySolidColorBrush", mySolidColorBrush)
myRectangle.Fill = mySolidColorBrush
Dim myDoubleAnimation As 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))
Dim myColorAnimation As 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))
Dim myStoryboard As New Storyboard()
myStoryboard.Children.Add(myDoubleAnimation)
myStoryboard.Children.Add(myColorAnimation)
AddHandler myRectangle.MouseEnter, Sub(sender As Object, e As MouseEventArgs) myStoryboard.Begin(Me)
myStackPanel.Children.Add(myRectangle)
Me.Content = myStackPanel
End Sub
End Class
End Namespace
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">
Dim myRectangle As New Rectangle()
myRectangle.Name = "MyRectangle"
' Create a name scope for the page.
NameScope.SetNameScope(Me, New NameScope())
Me.RegisterName(myRectangle.Name, myRectangle)
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))
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, directive 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" />
Dim mySolidColorBrush As New SolidColorBrush(Colors.Blue)
Me.RegisterName("MySolidColorBrush", mySolidColorBrush)
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.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 XAML 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" />
Dim propertyChain() As DependencyProperty = {Rectangle.FillProperty, SolidColorBrush.ColorProperty}
Dim thePath As String = "(0).(1)"
Dim myPropertyPath As New PropertyPath(thePath, propertyChain)
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath)
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 |
Where
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.
Dim propertyChain() As DependencyProperty = {Rectangle.FillProperty, SolidColorBrush.ColorProperty}
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) |
Where
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.
Dim propertyChain() As DependencyProperty = {Rectangle.FillProperty, SolidColorBrush.ColorProperty}
Dim thePath As String = "(0).(1)"
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(Me, New NameScope())
Dim rectangle01 As New Rectangle()
rectangle01.Name = "Rectangle01"
Me.RegisterName(rectangle01.Name, rectangle01)
rectangle01.Width = 100
rectangle01.Height = 100
rectangle01.Fill = CType(Me.Resources("MySolidColorBrushResource"), SolidColorBrush)
Dim myColorAnimation As New ColorAnimation()
myColorAnimation.From = Colors.Blue
myColorAnimation.To = Colors.AliceBlue
myColorAnimation.Duration = New Duration(TimeSpan.FromSeconds(1))
Storyboard.SetTargetName(myColorAnimation, rectangle01.Name)
Dim propertyChain() As DependencyProperty = {Rectangle.FillProperty, SolidColorBrush.ColorProperty}
Dim thePath As String = "(0).(1)"
Dim myPropertyPath As New PropertyPath(thePath, propertyChain)
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath)
Dim myStoryboard As New Storyboard()
myStoryboard.Children.Add(myColorAnimation)
Dim myBeginStoryboard As New BeginStoryboard()
myBeginStoryboard.Storyboard = myStoryboard
Dim myMouseEnterTrigger As New EventTrigger()
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent
myMouseEnterTrigger.Actions.Add(myBeginStoryboard)
rectangle01.Triggers.Add(myMouseEnterTrigger)
// 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 ].() |
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.
Dim propertyChain() As DependencyProperty = { Rectangle.RenderTransformProperty, TransformGroup.ChildrenProperty, RotateTransform.AngleProperty }
Dim thePath As String = "(0).(1)[1].(2)"
Dim myPropertyPath As New PropertyPath(thePath, propertyChain)
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath)
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.
Dim rectangle02 As New Rectangle()
rectangle02.Name = "Rectangle02"
Me.RegisterName(rectangle02.Name, rectangle02)
rectangle02.Width = 100
rectangle02.Height = 100
rectangle02.Fill = Brushes.Blue
rectangle02.RenderTransform = CType(Me.Resources("MyTransformGroupResource"), TransformGroup)
Dim myDoubleAnimation As New DoubleAnimation()
myDoubleAnimation.From = 0
myDoubleAnimation.To = 360
myDoubleAnimation.Duration = New Duration(TimeSpan.FromSeconds(1))
Storyboard.SetTargetName(myDoubleAnimation, rectangle02.Name)
Dim propertyChain() As DependencyProperty = { Rectangle.RenderTransformProperty, TransformGroup.ChildrenProperty, RotateTransform.AngleProperty }
Dim thePath As String = "(0).(1)[1].(2)"
Dim myPropertyPath As New PropertyPath(thePath, propertyChain)
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath)
Dim myStoryboard As New Storyboard()
myStoryboard.Children.Add(myDoubleAnimation)
Dim myBeginStoryboard As New BeginStoryboard()
myBeginStoryboard.Storyboard = myStoryboard
Dim myMouseEnterTrigger As New EventTrigger()
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent
myMouseEnterTrigger.Actions.Add(myBeginStoryboard)
rectangle02.Triggers.Add(myMouseEnterTrigger)
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 un storyboard en Extensible Application Markup Language (XAML), vous utilisez une action de déclencheur BeginStoryboard. BeginStoryboard distribue les animations aux objets et propriétés qu'elles animent et démarre le storyboard. (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.
Imports Microsoft.VisualBasic
Imports System
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
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.