Visão geral sobre Storyboards

Este tópico mostra como usar objetos Storyboard para organizar e aplicar animações. Ele descreve como manipular objetos Storyboard de forma interativa e descreve a sintaxe indireta para definir propriedades alvo.

Pré-requisitos

Para entender esse tópico, você deve estar familiarizado com os diferentes tipos de animação e seus recursos básicos. Para obter uma introdução a animação, consulte Revisão de Animação. Você também deve saber como usar propriedades anexadas. Para obter mais informações sobre propriedades anexadas, consulte Attached Properties Overview.

O que é um Storyboard?

Animações não são a única utilidade de cronograma. Outras classes de cronograma são fornecidas para ajudar você a organizar conjuntos de cronogramas e para aplicar cronogramas a propriedades. Cronogramas contêiner derivam da classe TimelineGroup e incluem ParallelTimeline e Storyboard.

Um Storyboard é um tipo de cronograma contêiner que fornece informações de direcionamento para o cronogramas que ele contém. Um storyboard pode conter qualquer tipo de Timeline, incluindo outras animações e cronogramas de contêiner. Storyboard objetos permitem agrupar cronogramas que afetam uma variedade de objetos e propriedades em uma árvore de única linha do tempo, facilitando a organizar e controlar comportamentos complexos de temporização. Por exemplo, suponha que você deseja um botão que faz essas três coisas.

  • Aumenta e altera a cor quando o usuário seleciona o botão.

  • Se reduz e, em seguida, aumenta de volta até seu tamanho original quando clicado.

  • Reduz e esmaece para 50 por cento da sua opacidade quando fica desativado.

Nesse caso, você tem vários conjuntos de animações que aplicar ao mesmo objeto, e você deseja reproduzir em diferentes momentos, dependentes do estado do botão. Storyboard objetos permitem que você organizar as animações e aplicá-las em grupos a um ou mais objetos.

Onde você pode usar um Storyboard?

Um Storyboard pode ser usado para animar propriedades de dependência de classes animáveis (para obter mais informações sobre o que torna uma classe animável, consulte Revisão de Animação). No entanto, como o uso de Storyboars é um recurso no nível do framework, o objeto deve pertencer ao NameScope de um FrameworkElement ou de um FrameworkContentElement.

Por exemplo, você poderia usar um Storyboard para fazer o seguinte:

No entanto, você não pode usar um Storyboard para animar um SolidColorBrush que não registrou seu nome com um FrameworkElement ou um FrameworkContentElement, ou não foi usado para definir uma propriedade de um FrameworkElement ou de um FrameworkContentElement.

Como aplicar animações com um Storyboard

Para usar um Storyboard para organizar e aplicar animações, você adiciona as animações como cronogramas filhos do Storyboard. A classe Storyboard fornece as propriedades anexadas Storyboard.TargetName e Storyboard.TargetProperty. Você define essas propriedades em uma animação para especificar seus objeto e propriedade alvo.

Para aplicar as animações aos seus alvos, você começa o Storyboard usando um método ou uma ação disparadores. Em XAML, você usa um objeto BeginStoryboard com um EventTrigger, Trigger, ou DataTrigger. Em código, você também pode usar o método Begin.

A tabela a seguir mostra diferentes lugares onde cada Storyboard começar a técnica é suportada: -instância, estilo, modelo de controle e modelo de dados. " Por instância"refere-se à técnica de aplicar uma animação ou storyboard diretamente às instâncias de um objeto, em vez de em um estilo, modelo de controle ou modelo de dados.

Um Storyboard é iniciado usando…

Por instância

Style

Modelos de controle

Modelos de dados

Exemplo

BeginStoryboard e um EventTrigger

Sim

Sim

Sim

Sim

Como: Animate a Property by Using a Storyboard

BeginStoryboard e uma propriedade Trigger

Não

Sim

Sim

Sim

Como: Trigger an Animation When a Property Value Changes

BeginStoryboard e um DataTrigger

Não

Sim

Sim

Sim

Como: Disparar uma Animação Quando os Dados Mudarem

Método Begin

Sim

Não

Não

Não

Como: Animate a Property by Using a Storyboard

O exemplo a seguir utiliza um Storyboard para animar a Width de um elemento Rectangle e a Color de um SolidColorBrush usado para pintar o 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;
        } 
    }
}

As seções a seguir descrevem as propriedades anexadas TargetName e TargetProperty em mais detalhes.

Definição de alvos dos tipos FrameworkElement, FrameworkContentElement e Freezables

A seção anterior mencionou que, para uma animação encontrar seu alvo, ela deve saber o nome do alvo e a propriedade a animar. Especificar a propriedade para animar é reta encaminhar: Basta conjunto Storyboard.TargetProperty com o nome da propriedade para animar. Você especifica o nome do objeto cuja propriedade você deseja animar definindo a propriedade Storyboard.TargetName na animação.

Para que a propriedade TargetName funcione, o objeto alvo deve ter um nome. Atribuir um nome para um FrameworkElement ou um FrameworkContentElement no XAML é diferente de atribuir um nome para um objeto Freezable.

Os elementos do framewrok são as classes que herdam da classe FrameworkElement. Exemplos de elementos do framework incluem Window, DockPanel, Button e Rectangle. Essencialmente todas as janelas, painéis e os controles são elementos. Os elementos de conteúdo do framewrok são as classes que herdam da classe FrameworkContentElement. Exemplos de elementos de conteúdo do framework incluem FlowDocument e Paragraph. Se você estiver em dúvida se um tipo é um elemento do framework ou um elemento de conteúdo do framework, verifique se ele tem uma propriedade Name. Se afirmativo, é provavelmente um elemento do framework ou um elemento de conteúdo do framework. Para ter certeza, verifique a seção hierarquia de herança da página do tipo.

Para permitir definir um elemento do framework ou um elemento de conteúdo do framework como alvo em XAML, você define sua propriedade Name. Em código, você também precisará usar o método RegisterName para registrar o nome do elemento no elemento para o qual você criou um NameScope.

O exemplo a seguir, extraído do exemplo anterior, atribui o nome MyRectangle a um Rectangle, um tipo 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);

Após ele ter um nome, você pode animar uma propriedade do elemento.

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

Os tipos Freezable são as classes que herdam da classe Freezable. Exemplos de Freezable incluem SolidColorBrush, RotateTransform e GradientStop.

Para permitir a definião de um Freezable como alvo para uma animação em XAML, você use o x:Name Attribute para atribuí-lo um nome. Em código, você usa o método RegisterName para registrar o nome do elemento no elemento para o qual você criou um NameScope.

O exemplo a seguir atribui um nome para um objeto Freezable.

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

O objeto, em seguida, pode ser alvo de uma animação.

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

Objetos Storyboard usam escopos de nome para resolver a propriedade TargetName. Para obter mais informações sobre escopos de nome no WPF, consulte Namescopes WPF. Se a propriedade TargetName for omitida, a animação afeta o elemento no qual ela está definida, ou, no caso de estilos, o elemento estilizado.

As vezes, um nome não pode ser atribuído a um objeto Freezable. Por exemplo, se um Freezable é declarado como um recurso ou é usado para definir um valor de propriedade em um estilo, não pode ser dado um nome a ele. Como ele não possui um nome, ele não pode ser alvo diretamente — mas ele pode ser alvo indiretamente. As seguintes seções descrevem como usar definição de alvo indireta.

Definição de alvo indireta

Há vezes que um Freezable não pode ser alvo diretamente de uma animação, como quando o Freezable é declarado como um recurso ou usado para definir um valor de propriedade em um estilo. Nesses casos, mesmo que você não possa definí-lo como alvo diretamente, você ainda pode animar o objeto Freezable. Em vez de definir a propriedade TargetName com o nome do Freezable, você atribui a ela o nome do elemento ao qual o Freezable "pertence." Por exemplo, um SolidColorBrush usado para definir o Fill de um elemento retângulo pertence a esse retângulo. Para animar o pincel, você poderia definir a TargetProperty da animação como uma cadeia de propriedades que começa na propriedade do elemento do framework ou elemento de conteúdo do framework que o Freezable foi usado para definir e termina com a propriedade do Freezable a animar.

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

Observe que, se o Freezable estiver congelado, um clone será feito, e este clone será animado. Quando isso acontecer, a propriedade HasAnimatedProperties do objeto original continua a retornar false, pois o objeto original não é realmente animado. Para mais informações sobre animação, consulte Visão geral sobre objetos Freezable.

Além disso, observe que, ao usar definição indireta de propriedades alvo, é possível ter como alvo objetos que não existem. Por exemplo, você pode assumir que o Background de um determinado botão foi definido com um SolidColorBrush e tentar animar sua cor, quando na verdade, um LinearGradientBrush foi usado para definir o plano de fundo do botão. Nesses casos, nenhuma exceção é acionada; a animação falhará em mostrar um efeito visível pois o LinearGradientBrush não reage a alterações na propriedade Color.

As seções a seguir descrevem em mais detalhes a sintaxe indireta para definir propriedades alvo.

Definindo indiretamente como alvo uma propriedade de uma Freezable em XAML

Para selecionar uma propriedade de um Freezable em XAML, use a sintaxe a seguir.

ElementPropertyName.FreezablePropertyName

Where

O código a seguir mostra como animar a Color de um SolidColorBrush usado para definir o

Fill de um elemento retângulo.

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

As vezes você precisa definir como alvo um Freezable contido em uma coleção ou vetor.

Para definir como alvo um Freezable contido em uma coleção, você usa a seguinte sintaxe de caminho.

ElementPropertyName.Children[CollectionIndex].FreezablePropertyName

Onde CollectionIndex é o índice do objeto no seu vetor ou coleção.

Por exemplo, suponha que um retângulo tem um recurso TransformGroup aplicado à sua propriedade RenderTransform, e você deseja animar uma das transformações que ele contém.

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

O código a seguir mostra como animar a propriedade Angle da RotateTransform mostrada no exemplo anterior.

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

Definindo indiretamente como alvo uma propriedade de uma Freezable em código

Em código, você cria um objeto PropertyPath. Ao criar o PropertyPath, você especifica um Path e PathParameters.

Para criar PathParameters, você criar um vetor do tipo DependencyProperty que contém uma lista de campos identificadores de propriedades de dependência. O primeiro campo identificador é para a propriedade do FrameworkElement ou FrameworkContentElement que o Freezable é usado para definir. O próximo campo identificador representa a propriedade alvo do Freezable. Pense nisso como uma cadeia de propriedades que conecta o Freezable ao objeto FrameworkElement.

O código a seguir é um exemplo de uma cadeia de propriedades de dependência que tem como alvo a Color de um SolidColorBrush usado para definir o Fill de um elemento retângulo.

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

Você também precisará especificar um Path. Um Path é uma String que informa ao Path como interpretar seus PathParameters. Ele usa a sintaxe a seguir:

(OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex)

Where

O exemplo a seguir mostra o Path que acompanharia os PathParameters definidos no exemplo anterior.

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

A exemplo a seguir combina o código dos exemplos anteriores para animar a Color de um SolidColorBrush usado para definir o Fill de um elemento retângulo.

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

As vezes você precisa definir como alvo um Freezable contido em uma coleção ou vetor. Por exemplo, suponha que um retângulo tem um recurso TransformGroup aplicado à sua propriedade RenderTransform, e você deseja animar uma das transformações que ele contém.

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

Para definir como alvo um Freezable contido em uma coleção, use a seguinte sintaxe de caminho.

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

Onde CollectionIndex é o índice do objeto no seu vetor ou coleção.

Para selecionar a propriedade Angle da RotateTransform, a segunda transformação no TransformGroup, você usaria os seguintes 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);

O exemplo a seguir mostra o código completo da animação do Angle de uma RotateTransform contida em um 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);

Definição indireta de alvo com um Freezable como ponto de início

As seções anteriores descreveram como definir indiretamente um Freezable como alvo iniciando com um FrameworkElement ou FrameworkContentElement e criaundo uma cadeia de propriedades para uma subpropriedade de um Freezable. Você também pode usar um Freezable como ponto de partida e indiretamente definir como alvo um das suas subpropriedades Freezable. Uma restrição adicional se aplica ao usar um Freezable sistema autônomo um ponto de partida para o direcionamento indiretos: o inicialFreezable e cada Freezable não devem ser congelados entre ele e subpropriedade indiretamente-alvo.

Controlando interativamente um Storyboard em XAML

Para iniciar um storyboard em Extensible Application Markup Language (XAML), você usar um BeginStoryboard ação do disparar. BeginStoryboard distribui as animações a objetos e propriedades que animar e inicia o storyboard. (Para obter detalhes sobre esse processo, consulte Visão Geral de Animação e Sistema de Tempo.) Se você der um nome ao BeginStoryboard, especificando sua propriedade Name, você irá torná-lo um storyboard controlável. Você pode então interativamente controlar o storyboard depois que ele é iniciado. A seguir está uma lista das ações controláveis de storyboard que você usa com os disparadores de eventos para controlar um storyboard.

No exemplo a seguir, ações de storyboard controláveis são usadas para controlar interativamente um 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>

Controlando um storyboard interativamente usando código

Os exemplos anteriores mostraram como animar usando ações disparadoras. Em código, você também pode controlar um storyboard usando métodos interativos da classe Storyboard. Para um Storyboard ser tornado interativo em código, você deve usar a sobrecarga apropriada do método Begin do storyboard e especificar true para torná-lo controlável. Consulte a página Begin(FrameworkElement, Boolean) para obter mais informações.

A lista a seguir mostra os métodos que podem ser usados para manipular um Storyboard após ele ter sido iniciado:

A vantagem de usar esses métodos é que você não precisa criar um Trigger ou objetos TriggerAction; basta uma referência ao Storyboard controlável que você deseja manipular.

Observação: Todas as ações interativas em um Clocke, portanto, também em um Storyboard ocorrerão na escala do mecanismo de tempo que irá acontecer logo antes de render próxima próxima. Por exemplo, se você usar o método Seek para saltar para outro ponto em uma animação, o valor da propriedade não é alterado imediatamente, em vez disso, o valor é alterado no tick seguinte do mecanismo de temporização.

O exemplo a seguir mostra como aplicar e controlar animações usando os métodos interativos da 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);

        }         

    }

}

Animar em um estilo

Você pode usar objetos Storyboard para definir animações em um Style. Animação com um Storyboard em um Style é semelhante ao uso de um Storyboard em outro lugar, com as seguintes três exceções:

  • Você não especifica um TargetName; o Storyboard sempre tem como alvo o elemento ao qual o Style é aplicado. Para definir objetos Freezable como alvo, você deve usar definição de alvo indireta. Para obter mais informações sobre definição indireta de alvos, consulte a seção Definição indireta de alvo.

  • Você não pode especificar um SourceName para um EventTrigger ou um Trigger.

  • Você não pode usar referências dinâmicas a recursos ou expressões de associação de dados para definir valores de propriedades de Storyboard ou de animação. Isso acontece porque tudo em um Style deve ser thread-safe, e o sistema de temporização deve Freeze objetos Storyboard para torná-los thread-safe. Um Storyboard não pode ser congelado se ele ou seus cronogramas filhos contiverem referências dinâmicas a recursos ou expressões de associação de dados. Para obter mais informações sobre congelamento e outros recursos Freezable, consulte Visão geral sobre objetos Freezable.

  • Em XAML, você não pode declarar manipuladores de eventos para eventos de Storyboard ou de animação.

Para obter um exemplo mostrando como definir um storyboard em um estilo, consulte o exemplo Como: Animar em um estilo.

Animar em um ControlTemplate

Você pode usar objetos Storyboard para definir animações em um ControlTemplate. Animação com um Storyboard em um ControlTemplate é semelhante ao uso de um Storyboard em outro lugar, com as seguintes duas exceções:

  • O TargetName somente pode se referir a objetos filho de ControlTemplate. Se TargetName não for especificado, a animação atinge o elemento ao qual o ControlTemplate é aplicado.

  • O SourceName para um EventTrigger ou um Trigger somente pode se referir a objetos filho de ControlTemplate.

  • Você não pode usar referências dinâmicas a recursos ou expressões de associação de dados para definir valores de propriedades de Storyboard ou de animação. Isso acontece porque tudo em um ControlTemplate deve ser thread-safe, e o sistema de temporização deve Freeze objetos Storyboard para torná-los thread-safe. Um Storyboard não pode ser congelado se ele ou seus cronogramas filhos contiverem referências dinâmicas a recursos ou expressões de associação de dados. Para obter mais informações sobre congelamento e outros recursos Freezable, consulte Visão geral sobre objetos Freezable.

  • Em XAML, você não pode declarar manipuladores de eventos para eventos de Storyboard ou de animação.

Para obter um exemplo mostrando como definir um storyboard em um ControlTemplate, consulte o exemplo Como: Animar em um ControlTemplate.

Animar quando o valor de uma propriedade é alterado

Em estilos e modelos de controle, você pode usar objetos disparadores para iniciar um storyboard quando uma propriedade é alterada. Para exemplos, veja Como: Trigger an Animation When a Property Value Changes e Como: Animar em um ControlTemplate.

Animações aplicadas por objetos Trigger de propriedade se comportam de maneira mais complexa do que animações EventTrigger ou animações iniciadas usando métodos de Storyboard. Elas "entregam" para animações definidas por outros objetos Trigger, mas se compõem com animações por EventTrigger e animações acionadas por método.

Consulte também

Conceitos

Revisão de Animação

Visão geral de técnicas de animação de propriedades

Visão geral sobre objetos Freezable