Cenni preliminari sugli storyboard

Aggiornamento: novembre 2007

In questo argomento viene illustrato come utilizzare gli oggetti Storyboard per organizzare e applicare animazioni. Viene illustrato come modificare in modo interattivo gli oggetti Storyboard e come utilizzare la sintassi indiretta relativa alle proprietà.

Prerequisiti

Per comprendere questo argomento, è necessario conoscere i diversi tipi di animazione e le relative funzionalità di base. Per un'introduzione alle animazioni, vedere Cenni preliminari sull'animazione. È inoltre consigliabile conoscere le modalità di utilizzo delle proprietà collegate. Per ulteriori informazioni sulle proprietà collegate, vedere Cenni preliminari sulle proprietà associate.

Definizione di storyboard

Le animazioni non sono l'unico tipo utile di sequenza temporale. Vengono fornite altre classi di sequenze temporali per organizzare insiemi di sequenze e per applicare sequenze alle proprietà. Le sequenze temporali contenitore derivano dalla classe TimelineGroup e includono ParallelTimeline e Storyboard.

Uno Storyboard è un tipo di sequenza temporale contenitore che fornisce informazioni per le sequenze in essa contenute. Uno storyboard può contenere qualsiasi tipo di Timeline, incluse altre animazioni e altre sequenze temporali contenitore. Gli oggetti Storyboard consentono di combinare sequenze temporali che influiscono su numerosi oggetti e proprietà in una singola struttura ad albero di sequenze, semplificando l'organizzazione e il controllo di comportamenti di temporizzazione complessi. Si supponga, ad esempio, di voler disporre di un pulsante avente le tre caratteristiche riportate di seguito.

  • Aumentare di volume e cambiare colore quando viene selezionato.

  • Ridursi e tornare nuovamente alle dimensioni originali quando viene fatto clic su di esso.

  • Comprimersi e perdere un 50 percento di opacità quando viene disattivato.

In questo caso, si dispone di più insiemi di animazioni applicabili allo stesso oggetto ed eseguibili in momenti diversi, a seconda dello stato del pulsante. Gli oggetti Storyboard consentono di organizzare le animazioni e di applicarle in gruppi a uno o più oggetti.

Dove utilizzare uno storyboard

Un oggetto Storyboard può essere utilizzato per animare le proprietà di dipendenza di classi che supportano l'animazione. Per ulteriori informazioni sul supporto delle classi per le animazioni, vedere Cenni preliminari sull'animazione). Poiché lo storyboard è una funzionalità a livello di framework, l'oggetto deve appartenere all'oggetto NameScope di FrameworkElement o di FrameworkContentElement.

È ad esempio possibile utilizzare uno Storyboard per eseguire le operazioni riportate di seguito:

Non è tuttavia possibile utilizzare uno Storyboard per animare un oggetto SolidColorBrush che non ha registrato il proprio nome con FrameworkElement o FrameworkContentElement oppure che non è stato utilizzato per impostare una proprietà di un oggetto FrameworkElement o FrameworkContentElement.

Come applicare animazioni con uno storyboard

Per utilizzare uno Storyboard per organizzare e applicare animazioni, è necessario aggiungere le animazioni come sequenze temporali figlio dello Storyboard. La classe Storyboard fornisce le proprietà collegate Storyboard.TargetName e Storyboard.TargetProperty. Queste proprietà devono essere impostate su un'animazione per specificare la proprietà e l'oggetto di destinazione relativi.

Per applicare animazioni alle relative destinazioni, dare inizio allo Storyboard utilizzando un'azione trigger o un metodo. In XAML, utilizzare un oggetto BeginStoryboard con EventTrigger, Trigger o DataTrigger. Nel codice, è anche possibile utilizzare il metodo Begin.

Nella tabella riportata di seguito sono riportate le diverse posizioni in cui è supportata la tecnica di inizio di ciascuno Storyboard: per istanza, stile, modello di controllo e modello di dati. "Per istanza" si riferisce alla tecnica di applicare un'animazione o uno storyboard direttamente a istanze di un oggetto, piuttosto che in uno stile, un modello di controllo o un modello di dati.

Storyboard iniziato utilizzando…

Per istanza

Style

Modello di controllo

Modello di dati

Esempio

BeginStoryboard e EventTrigger

Procedura: animare una proprietà utilizzando uno storyboard

BeginStoryboard e Trigger della proprietà

No

Procedura: attivare un'animazione quando il valore di una proprietà viene modificato

BeginStoryboard e DataTrigger

No

Procedura: attivare un'animazione quando i dati vengono modificati

Metodo Begin

No

No

No

Procedura: animare una proprietà utilizzando uno storyboard

Nell'esempio riportato di seguito viene utilizzato uno Storyboard per animare la proprietà Width di un elemento Rectangle e la proprietà Color di un oggetto SolidColorBrush utilizzato per disegnare quel 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;
        } 
    }
}

Nelle sezioni riportate di seguito vengono descritte più dettagliatamente le proprietà collegate TargetName e TargetProperty.

Elementi del framework, elementi di contenuto del framework e oggetti Freezable

Nella sezione precedente è stato specificato che per trovare la relativa destinazione un'animazione deve conoscere il nome e la proprietà da animare relativi. Per specificare la proprietà da animare,è sufficiente impostare la proprietà Storyboard.TargetProperty con il nome della proprietà da animare. Specificare il nome dell'oggetto di cui animare la proprietà impostando la proprietà Storyboard.TargetName sull'animazione.

Affinché la proprietà TargetName sia funzionante, l'oggetto di destinazione deve avere un nome. La procedura di assegnazione di un nome a un oggetto FrameworkElement o FrameworkContentElement in XAML non corrisponde a quella per assegnare un nome a un oggetto Freezable.

Gli elementi del framework sono classi che ereditano dalla classe FrameworkElement. Elementi del framework di questo tipo sono rappresentati ad esempio da Window, DockPanel, Button e Rectangle. Praticamente tutte le finestre, i pannelli e i controlli sono elementi. Gli elementi di contenuto del framework sono classi che ereditano dalla classe FrameworkContentElement. Elementi di contenuto del framework di questo tipo sono rappresentati ad esempio da FlowDocument e Paragraph. Se non si è in grado di stabilire se un tipo è un elemento del framework o un elemento di contenuto del framework, verificare se dispone della proprietà Name. In caso affermativo, si tratta probabilmente di un elemento del framework o di un elemento di contenuto del framework. Per avere la certezza, controllare la sezioneGerarchia di ereditarietà della pagina relativa al tipo.

Per utilizzare come destinazione un elemento del framework o un elemento di contenuto del framework in XAML, impostare la relativa proprietà Name. Nel codice è inoltre necessario utilizzare il metodo RegisterName per registrare il nome dell'elemento con l'elemento per il quale è stato creato un oggetto NameScope.

Nell'esempio riportato di seguito, ricavato dall'esempio precedente, viene assegnato il nome MyRectangle a Rectangle, un tipo di 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);

Dopo l'assegnazione del nome all'elemento, è possibile animare una proprietà.

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

I tipi Freezable sono classi che ereditano dalla classe Freezable. Esempi di oggetti Freezable includono SolidColorBrush, RotateTransform e GradientStop.

Per utilizzare come destinazione un oggetto Freezable tramite un'animazione in XAML, utilizzare Attributo x:Name per assegnare ad esso un nome. Nel codice utilizzare il metodo RegisterName per registrare il suo nome con l'elemento per il quale è stato creato un oggetto NameScope.

Nell'esempio riportato di seguito viene assegnato un nome all'oggetto Freezable.

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

L'oggetto può essere impostato come destinazione di un'animazione.

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

Gli oggetti Storyboard utilizzano ambiti di nomi per risolvere la proprietà TargetName. Per ulteriori informazioni sugli ambiti di nomi WPF, vedere Ambiti dei nomi WPF. Se si omette la proprietà TargetName, l'animazione considera come destinazione l'elemento su cui è stata definita o, nel caso di stili, l'elemento con stile.

Talvolta non è possibile assegnare un nome a un oggetto Freezable. Se, ad esempio, un oggetto Freezable viene dichiarato come una risorsa o utilizzato per impostare un valore di proprietà in uno stile, non è possibile assegnare ad esso un nome. Poiché non dispone di un nome, non può essere impostato direttamente come destinazione, ma solo indirettamente. Nelle sezioni riportate di seguito viene illustrato come impostare indirettamente le destinazioni.

Impostazione indiretta delle destinazioni

In alcuni casi, un oggetto Freezable non può essere impostato direttamente come destinazione da un'animazione, ad esempio quando l'oggetto Freezable viene dichiarato come una risorsa o utilizzato per impostare un valore di proprietà in uno stile. In questi casi, anche se non è possibile impostarlo direttamente come destinazione, è ancora possibile animare l'oggetto Freezable. Anziché impostare la proprietà TargetName con il nome dell'oggetto Freezable, assegnare ad esso il nome dell'elemento a cui "appartiene" l'oggetto Freezable. Ad esempio, un oggetto SolidColorBrush utilizzato per impostare la proprietà Fill di un elemento rettangolo appartiene a quel rettangolo. Per animare il pennello, impostare la proprietà TargetProperty dell'animazione con una catena di proprietà che inizia dalla proprietà dell'elemento del framework o dell'elemento di contenuto del framework impostato con l'oggetto Freezable e termina con la proprietà Freezable da animare.

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

Se l'oggetto Freezable è bloccato, viene creato un duplicato e tale duplicato verrà animato. In questo caso, la proprietà HasAnimatedProperties dell'oggetto originale continua a restituire false, perché l'oggetto originale non è effettivamente animato. Per ulteriori informazioni sulla duplicazione, vedere Cenni preliminari sugli oggetti Freezable.

Quando si impostano indirettamente le destinazioni delle proprietà, è possibile impostare come destinazioni oggetti che non esistono. Si supponga, ad esempio, che la proprietà Background di un pulsante sia stata impostata con un oggetto SolidColorBrush e si sia tentato di animare la relativa proprietà Color quando in realtà era stato utilizzato un oggetto LinearGradientBrush per impostare la proprietà Background del pulsante. In questi casi, non viene generata alcuna eccezione; l'animazione non avrà un effetto visibile perché LinearGradientBrush non reagisce alle modifiche apportate alla proprietà Color.

Nelle sezioni riportate di seguito viene illustrato in dettaglio come impostare in modo indiretto le destinazioni delle proprietà.

Impostazione indiretta della destinazione di una proprietà di un oggetto Freezable in XAML

Per impostare come destinazione una proprietà di un oggetto Freezable in XAML, utilizzare la sintassi riportata di seguito.

ElementPropertyName.FreezablePropertyName

Percorso

  • ElementPropertyName è la proprietà dell'oggetto FrameworkElement impostato tramite l'oggetto Freezable e

  • FreezablePropertyName è la proprietà dell'oggetto Freezable da animare.

Nel codice riportato di seguito viene illustrato come animare la proprietà Color di un oggetto SolidColorBrush utilizzato per la proprietà

Fill di un elemento rettangolo.

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

Talvolta, è necessario impostare come destinazione un oggetto Freezable contenuto in un insieme o in una matrice.

Per impostare come destinazione un oggetto Freezable contenuto in un insieme, utilizzare la sintassi del percorso riportata di seguito.

ElementPropertyName.Children[CollectionIndex].FreezablePropertyName

Dove CollectionIndex è l'indice dell'oggetto nella matrice o nell'insieme.

Si supponga, ad esempio, che alla proprietà RenderTransform di un rettangolo sia applicata una risorsa TransformGroup e di volere animare una delle trasformazioni in essa contenute.

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

Nell'esempio di codice riportato di seguito viene illustrato come animare la proprietà Angle dell'oggetto RotateTransform illustrato nel precedente esempio.

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

Impostazione indiretta della destinazione di una proprietà di un oggetto Freezable nel codice

Nel codice creare un oggetto PropertyPath. Quando si crea l'oggetto PropertyPath, si specifica una proprietà Path e una proprietà PathParameters.

Per creare PathParameters, si crea una matrice di tipo DependencyProperty che contiene un elenco di campi dell'identificatore di proprietà di dipendenza. Il primo campo dell'identificatore è per la proprietà dell'oggetto FrameworkElement o FrameworkContentElement impostato tramite l'oggetto Freezable. Il campo dell'identificatore successivo rappresenta la proprietà dell'oggetto Freezable da impostare come destinazione. Considerarlo come una catena di proprietà che collega l'oggetto Freezable all'oggetto FrameworkElement.

Di seguito è riportato un esempio di una catena di proprietà di dipendenza che imposta come destinazione la proprietà Color di un oggetto SolidColorBrush utilizzato per impostare la proprietà Fill di un elemento rettangolo.

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

È inoltre necessario specificare una proprietà Path. Path è un oggetto String che indica alla proprietà Path come interpretare la proprietà PathParameters. Viene utilizzata la seguente sintassi.

(OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex)

Percorso

  • OwnerPropertyArrayIndex è l'indice della matrice DependencyProperty che contiene l'identificatore della proprietà dell'oggetto FrameworkElement impostato tramite Freezable e

  • FreezablePropertyArrayIndex è l'indice della matrice DependencyProperty che contiene l'identificatore della proprietà da impostare come destinazione.

Nell'esempio riportato di seguito viene illustrata la proprietà Path associata alla proprietà PathParameters definita nel precedente esempio.

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

Nell'esempio riportato di seguito viene combinato il codice degli esempi precedenti per animare la proprietà Color di un oggetto SolidColorBrush utilizzato per impostare la proprietà Fill di un elemento rettangolo.

// 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);

Talvolta, è necessario impostare come destinazione un oggetto Freezable contenuto in un insieme o in una matrice. Si supponga, ad esempio, che alla proprietà RenderTransform di un rettangolo sia applicata una risorsa TransformGroup e di volere animare una delle trasformazioni in essa contenute.

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

Per impostare come destinazione un oggetto Freezable contenuto in un insieme, utilizzare la sintassi del percorso riportata di seguito.

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

Dove CollectionIndex è l'indice dell'oggetto nella matrice o nell'insieme.

Per impostare come destinazione la proprietà Angle dell'oggetto RotateTransform, la seconda trasformazione in TransformGroup, utilizzare le proprietà Path e 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);

Nell'esempio riportato di seguito viene illustrato il codice completo per animare la proprietà Angle di un oggetto RotateTransform contenuto in 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);

Impostazione indiretta della destinazione con un oggetto Freezable come punto di partenza

Nelle sezioni precedenti veniva illustrato come impostare indirettamente come destinazione un oggetto Freezable partendo da un oggetto FrameworkElement o FrameworkContentElement e creando una catena di proprietà a una proprietà secondaria Freezable. È inoltre possibile utilizzare un oggetto Freezable come punto di partenza e impostare indirettamente come destinazione una delle proprietà secondarie dell'oggetto Freezable. È tuttavia necessario tenere conto di un'ulteriore limitazione quando si utilizza un oggetto Freezable come punto di partenza per l'impostazione indiretta delle destinazioni: l'oggetto Freezable iniziale e ogni oggetto Freezable presente tra esso e la proprietà secondaria impostata indirettamente come destinazione non deve essere bloccato.

Controllo interattivo di uno storyboard in XAML

Per avviare uno storyboard in Extensible Application Markup Language (XAML), utilizzare un'azione trigger BeginStoryboard. BeginStoryboard distribuisce le animazioni agli oggetti e alle proprietà animate e avvia lo storyboard. Per informazioni dettagliate su questo processo, vedere Cenni preliminari sull'animazione e sul sistema di temporizzazione. Se si assegna un nome allo BeginStoryboard specificando la relativa proprietà Name, è possibile renderlo controllabile. È quindi possibile controllare in modo interattivo lo storyboard dopo il suo avvio. Di seguito è riportato un elenco di azioni dello storyboard controllabili che è possibile utilizzare con trigger di evento per controllare uno storyboard.

Nell'esempio riportato di seguito vengono utilizzate azioni di storyboard controllabili per controllare in modo interattivo uno storyboard.

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

Controllo interattivo di uno storyboard tramite il codice

Negli esempi precedenti veniva illustrato come eseguire animazioni utilizzando azioni trigger. Nel codice, è inoltre possibile controllare uno storyboard utilizzando metodi interattivi della classe Storyboard. Per rendere interattivo uno Storyboard nel codice, è necessario utilizzare l'overload appropriato del metodo Begin dello storyboard e specificare true per renderlo controllabile. Per ulteriori informazioni, vedere la pagina Begin(FrameworkElement, Boolean).

Di seguito sono elencati i metodi che è possibile utilizzare per modificare uno Storyboard dopo il suo avvio:

Il vantaggio derivante dall'utilizzo di questi metodi è che non è necessario creare oggetti Trigger o TriggerAction; è sufficiente disporre di un riferimento allo Storyboard controllabile che si desidera modificare.

Nota: tutte le azioni interattive eseguite in un oggetto Clock, e di conseguenza in uno Storyboard avranno luogo in corrispondenza del tick successivo del motore di temporizzazione che precederà di poco il rendering successivo. Ad esempio, se si utilizza il metodo Seek per passare a un altro punto di un'animazione, il valore della proprietà non cambia immediatamente, ma al tick successivo del motore di temporizzazione.

Nell'esempio riportato di seguito viene illustrato come applicare e controllare le animazioni utilizzando i metodi interattivi della 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);

        }         

    }

}

Animazione in uno stile

È possibile utilizzare gli oggetti Storyboard per definire animazioni in uno Style. L'esecuzione di animazioni con uno Storyboard in uno Style presenta delle analogie con l'utilizzo di uno Storyboard in altre situazioni, con le tre eccezioni seguenti:

  • Non si specifica una proprietà TargetName; lo Storyboard imposta sempre come destinazione l'elemento a cui viene applicato lo Style. Per impostare come destinazione gli oggetti Freezable, è necessario utilizzare la modalità indiretta. Per ulteriori informazioni sulla modalità indiretta, vedere la sezione Impostazione indiretta delle destinazioni.

  • Non è possibile specificare una proprietà SourceName per un oggetto EventTrigger o Trigger.

  • Non è possibile utilizzare espressioni di associazione dati o riferimenti di risorsa dinamici per impostare valori di proprietà di Storyboard o animazioni perché quanto contenuto in uno Style deve essere thread-safe e il sistema di temporizzazione deve utilizzare il metodo Freeze sugli oggetti Storyboard per renderli thread-safe. Non è possibile bloccare uno Storyboard se lo storyboard stesso e le relative sequenze temporali figlio contengono espressioni di associazione dati o riferimenti di risorsa dinamici. Per ulteriori informazioni sul blocco e su altre funzionalità Freezable, vedere Cenni preliminari sugli oggetti Freezable.

  • In XAML, non è possibile dichiarare gestori eventi per eventi animazione o Storyboard.

Per un esempio in cui viene illustrato come dichiarare uno storyboard in uno stile, vedere l'esempio Procedura: aggiungere un'animazione in uno stile.

Animazione in un ControlTemplate

È possibile utilizzare gli oggetti Storyboard per definire animazioni in un oggetto ControlTemplate. L'esecuzione di animazioni con uno Storyboard in un oggetto ControlTemplate presenta delle analogie con l'utilizzo di uno Storyboard in altre situazioni, con le due eccezioni seguenti:

  • La proprietà TargetName può unicamente fare riferimento agli oggetti figlio dell'oggetto ControlTemplate. La proprietà TargetName non è specificata, la destinazione dell'animazione è rappresentata dall'elemento a cui viene applicato l'oggetto ControlTemplate.

  • La proprietà SourceName di un oggetto EventTrigger o Trigger può unicamente fare riferimento agli oggetti figlio dell'oggetto ControlTemplate.

  • Non è possibile utilizzare espressioni di associazione dati o riferimenti di risorsa dinamici per impostare valori di proprietà di Storyboard o animazioni perché quanto contenuto in uno ControlTemplate deve essere thread-safe e il sistema di temporizzazione deve utilizzare il metodo Freeze sugli oggetti Storyboard per renderli thread-safe. Non è possibile bloccare uno Storyboard se lo storyboard stesso e le relative sequenze temporali figlio contengono espressioni di associazione dati o riferimenti di risorsa dinamici. Per ulteriori informazioni sul blocco e su altre funzionalità Freezable, vedere Cenni preliminari sugli oggetti Freezable.

  • In XAML, non è possibile dichiarare gestori eventi per eventi animazione o Storyboard.

Per un esempio in cui viene illustrato come definire uno storyboard in un oggetto ControlTemplate, vedere l'esempio Procedura: eseguire un'animazione in un oggetto ControlTemplate.

Esecuzione di un'animazione quando viene modificato il valore di una proprietà

Negli stili e nei modelli di controllo, è possibile utilizzare oggetti Trigger per avviare uno storyboard alla modifica di una proprietà. Per i relativi esempi, vedere Procedura: attivare un'animazione quando il valore di una proprietà viene modificato e Procedura: eseguire un'animazione in un oggetto ControlTemplate.

Le animazioni applicate tramite oggetti Trigger di proprietà dimostrano un comportamento più complesso rispetto alle animazioni EventTrigger o a quelle avviate tramite i metodi Storyboard. Vengono fornite con animazioni definite da altri oggetti Trigger, ma possono essere combinate con animazioni EventTrigger e con animazioni attivate tramite metodi.

Vedere anche

Concetti

Cenni preliminari sull'animazione

Cenni preliminari sulle tecniche di animazione delle proprietà

Cenni preliminari sugli oggetti Freezable