Compartilhar via


Visão geral de storyboards

Este tópico mostra como usar Storyboard objetos para organizar e aplicar animações. Ele descreve como manipular Storyboard objetos interativamente e descreve a sintaxe de direcionamento de propriedade indireta.

Pré-requisitos

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

O que é um storyboard

Animações não são o único tipo útil de linha do tempo. Outras classes de linha do tempo são fornecidas para ajudá-lo a organizar conjuntos de linhas do tempo e aplicar linhas do tempo às propriedades. As linhas do tempo do contêiner derivam da TimelineGroup classe e incluem ParallelTimeline e Storyboard.

Um Storyboard é um tipo de linha do tempo de contêiner que fornece informações de direcionamento para as linhas do tempo que ele contém. Um Storyboard pode conter qualquer tipo de Timeline, incluindo outras linhas do tempo e animações de contêiner. Storyboard os objetos permitem combinar linhas do tempo que afetam uma variedade de objetos e propriedades em uma única árvore da linha do tempo, facilitando a organização e o controle de comportamentos de tempo complexos. Por exemplo, suponha que você queira um botão que faça essas três coisas.

  • Cresça e mude de cor quando o usuário selecionar o botão.

  • Diminua de tamanho e depois volte ao seu tamanho original quando clicado.

  • Encolha e esmaeça para 50% de opacidade quando ficar desabilitado.

Nesse caso, você tem vários conjuntos de animações que se aplicam ao mesmo objeto e deseja reproduzir em momentos diferentes, dependendo do estado do botão. Storyboard os objetos permitem organizar 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 animatáveis (para obter mais informações sobre o que torna uma classe animatable, consulte a Visão geral da animação). No entanto, como o storyboarding é um recurso no nível de estrutura, o objeto deve pertencer a um NameScope, um FrameworkElement ou um FrameworkContentElement.

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

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

Como aplicar animações com um storyboard

Para usar um Storyboard para organizar e aplicar animações, adicione as animações como timelines filhas do Storyboard. A classe Storyboard fornece as propriedades anexadas Storyboard.TargetName e Storyboard.TargetProperty. Você define essas propriedades em uma animação para especificar seu objeto de destino e propriedade.

Para aplicar animações aos seus destinos, você inicia o Storyboard com uma ação de gatilho ou um método. No XAML, você usa um BeginStoryboard objeto com um EventTrigger, Triggerou DataTrigger. No código, você também pode usar o Begin método.

A tabela a seguir mostra os diferentes locais em que cada Storyboard técnica de início tem suporte: por 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 um estilo, modelo de controle ou modelo de dados.

O processamento do storyboard é iniciado usando... Por instância Estilo Modelo de controle Modelo de dados Exemplo
BeginStoryboard e um EventTrigger Sim Sim Sim Sim Animar uma propriedade usando um storyboard
BeginStoryboard e uma propriedade Trigger Não Sim Sim Sim Disparar uma animação quando um valor de propriedade for alterado
BeginStoryboard e uma propriedade MultiTrigger Não Sim Sim Sim Exemplo da classe MultiTrigger
BeginStoryboard e um DataTrigger Não Sim Sim Sim Como disparar uma animação quando os dados são alterados
BeginStoryboard e um MultiDataTrigger Não Sim Sim Sim Exemplo da classe MultiDataTrigger
método Begin Sim Não Não Não Animar uma propriedade usando um storyboard

O exemplo a seguir usa um Storyboard para animar o WidthRectangle elemento e o Color de um SolidColorBrush usado para pintar esse Rectangle.

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

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

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

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

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

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

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

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

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

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

Direcionamento de Elementos de Estrutura, Elementos de Conteúdo de Estrutura e Elementos Congeláveis

A seção anterior mencionou que, para que uma animação encontre seu alvo, ela deve saber o nome do alvo e a propriedade a ser animada. Especificar a propriedade a ser animada é direto: basta definir TargetProperty com o nome da propriedade a ser animada. Especifique o nome do objeto cuja propriedade você deseja animar definindo a Storyboard.TargetName propriedade na animação.

Cuidado

Embora você possa usar a propriedade Target para associar diretamente a um objeto, como alternativa a TargetName, ela não é serializável. Não há garantia de que o Target objeto possa ser referenciado corretamente em XAML.

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

Elementos da estrutura são as classes que herdam da FrameworkElement classe. Exemplos de elementos da estrutura incluem Window, DockPanele ButtonRectangle. Essencialmente, todas as janelas, painéis e controles são elementos. Elementos de conteúdo da estrutura são as classes que herdam da FrameworkContentElement classe. Exemplos de elementos de conteúdo da estrutura incluem FlowDocument e Paragraph. Se você não tiver certeza se um tipo é um elemento de estrutura ou um elemento de conteúdo da estrutura, verifique se ele tem uma propriedade Name. Se isso acontecer, provavelmente será um elemento de estrutura ou um elemento de conteúdo da estrutura. Para ter certeza, verifique a seção Hierarquia de Herança de sua página de tipo.

Para permitir o direcionamento de um elemento de estrutura ou de um elemento de conteúdo de estrutura em XAML, é necessário definir a propriedade Name desse elemento. No código, você também precisa usar o RegisterName método para registrar o nome do elemento com o elemento para o qual você criou um NameScope.

O exemplo a seguir, obtido do exemplo anterior, atribui o nome MyRectangle a 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);

Depois que ele tiver um nome, você poderá animar uma propriedade desse 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 aquelas classes que herdam da classe Freezable. Exemplos de Freezable incluem SolidColorBrush, RotateTransform e GradientStop.

Para habilitar o direcionamento de um Freezable por uma animação em XAML, você usa a Diretiva x:Name para atribuir-lhe um nome. No código, você usa o método RegisterName para registrar seu nome junto ao elemento para o qual você criou um NameScope.

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

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

Em seguida, o objeto pode ser direcionado por 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));

Os objetos Storyboard usam escopos de nome para resolver a propriedade TargetName. Para obter mais informações sobre escopos de nome do WPF, consulte Namescopes XAML do WPF. Se a propriedade TargetName for omitida, a animação direcionará o elemento onde é definida ou, no caso de estilos, o elemento estilizado.

Às vezes, um nome não pode ser atribuído a um Freezable objeto. Por exemplo, se um Freezable for declarado como um recurso ou usado para definir um valor de propriedade em um estilo, ele não poderá receber um nome. Como ele não tem um nome, ele não pode ser direcionado diretamente, mas pode ser direcionado indiretamente. As seções a seguir descrevem como usar o direcionamento indireto.

Direcionamento indireto

Há ocasiões em que não é possível direcionar Freezable diretamente por animação, como quando Freezable é declarado como recurso ou usado para definir o valor de uma propriedade em um estilo. Nesses casos, mesmo que você não possa direcioná-lo diretamente, você ainda pode animar o Freezable objeto. Em vez de definir a TargetName propriedade com o nome do Freezable, você lhe dá o nome do elemento ao qual o Freezable "pertence". Por exemplo, um SolidColorBrush usado para definir o Fill elemento de retângulo pertence a esse retângulo. Para animar o pincel, você configuraria a animação TargetProperty com uma cadeia de propriedades que começa na propriedade do elemento do framework ou do elemento de conteúdo do framework que Freezable foi usado para definir e termina com a propriedade Freezable a ser animada.

<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 esse clone será animado. Quando isso acontece, a propriedade do HasAnimatedProperties objeto original continua a retornar false, porque o objeto original não é realmente animado. Para obter mais informações sobre clonagem, consulte a Visão Geral dos Freezable Objects.

Observe também que, ao usar o direcionamento de propriedade indireto, é possível direcionar objetos que não existem. Por exemplo, você pode assumir que a Background de um botão específico foi definida 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 é gerada; a animação não tem um efeito visível porque LinearGradientBrush não reage a alterações na Color propriedade.

As seções seguintes descrevem em detalhes a sintaxe para direcionamento indireto de propriedade.

Direcionando indiretamente uma propriedade de um Freezable em XAML

Para direcionar uma propriedade de um objeto congelável em XAML, use a sintaxe seguinte.

Sintaxe de propriedade
ElementPropertyName.FreezablePropertyName

Onde

  • ElementPropertyName é a propriedade da FrameworkElement qual o Freezable é usado para definir e

  • FreezablePropertyName é a propriedade do Freezable que se deseja animar.

O código a seguir mostra como animar o Color de um SolidColorBrush usado para definir o Fill elemento de um 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>

Às vezes, você precisa direcionar um freezable contido em uma coleção ou matriz.

Para direcionar um objeto do tipo freezable contido em uma coleção, use a sintaxe de caminho abaixo.

Sintaxe de path
ElementPropertyName.Children[CollectionIndex].FreezablePropertyName

Onde CollectionIndex é o índice do objeto em sua matriz ou coleção.

Por exemplo, suponha que um retângulo tenha um TransformGroup recurso aplicado à sua RenderTransform propriedade e você queira 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 do RotateTransform, mostrado 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>  

Direcionando indiretamente uma propriedade de um Freezable no código

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

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

Veja a seguir um exemplo de uma cadeia de propriedades de dependência que tem como destino o Color de um SolidColorBrush usado para definir o Fill elemento de um retângulo.

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

Você também precisa especificar um Path. A Path é um String que orienta Path sobre como interpretar seu PathParameters. Ele usa a sintaxe a seguir.

Sintaxe do caminho da propriedade
( OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex)

Onde

  • OwnerPropertyArrayIndex é o índice da DependencyProperty matriz que contém o identificador da propriedade do objeto FrameworkElement para a qual Freezable é usado para definir.

  • FreezablePropertyArrayIndex é o índice da DependencyProperty matriz que contém o identificador da propriedade que se deseja direcionar.

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

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

O exemplo a seguir combina o código nos exemplos anteriores para animar o Color de um SolidColorBrush usado para definir o Fill 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);

Às vezes, você precisa direcionar um freezable contido em uma coleção ou matriz. Por exemplo, suponha que um retângulo tenha um TransformGroup recurso aplicado à sua RenderTransform propriedade e você queira animar uma das transformações que ele contém.

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

Para direcionar um Freezable contido em uma coleção, use a sintaxe de caminho abaixo.

Sintaxe de path
( OwnerPropertyArrayIndex).(CollectionChildrenPropertyArrayIndex)[CollectionIndex].(FreezablePropertyArrayIndex)

Onde CollectionIndex é o índice do objeto em sua matriz ou coleção.

Para direcionar a propriedade Angle da RotateTransform, a segunda transformação de TransformGroup, você usaria o seguinte 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 para animar o Angle de um RotateTransform contido 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);

Direcionamento indireto, tendo um objeto congelável como ponto de partida

As seções anteriores descreveram como direcionar indiretamente um Freezable iniciando com um FrameworkElement ou FrameworkContentElement e criando uma cadeia de propriedades para uma Freezable sub-propriedade. Você também pode começar com um Freezable e direcionar indiretamente uma de suas Freezable sub-propriedades. Uma restrição adicional se aplica ao usar um Freezable como ponto de partida para direcionamento indireto: a inicial Freezable e cada Freezable entre ela e a sub-propriedade de destino indiretamente não deve estar congelada.

Controlando interativamente um storyboard em XAML

Para iniciar um storyboard em XAML (Extensible Application Markup Language), use uma BeginStoryboard ação de gatilho. BeginStoryboard distribui as animações para os objetos e propriedades animados e inicia o storyboard. (Para obter detalhes sobre este processo, consulte a Visão geral do sistema de animação e cronograma.) Se você der um nome à BeginStoryboard especificando sua propriedade Name, você a tornará um storyboard controlável. Em seguida, você pode controlar interativamente o storyboard depois que ele for iniciado. A seguir, uma lista de ações do storyboard que você pode controlar usando gatilhos de evento para gerenciar um storyboard.

No exemplo a seguir, as ações controláveis do storyboard são usadas para controlar interativamente um storyboard.

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

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

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

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

Controlando interativamente um storyboard usando código

Os exemplos anteriores mostraram como animar usando ações de gatilho. No código, você também pode controlar um storyboard usando métodos interativos da Storyboard classe. Para tornar Storyboard interativo no código, você deve usar a sobrecarga apropriada do método do storyboard e especificar Begin para que seja controlável. Consulte a Begin(FrameworkElement, Boolean) página para obter mais informações.

A lista a seguir mostra os métodos que podem ser usados para manipular um Storyboard após o início:

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

Observação

Todas as ações interativas realizadas em um Clock e, portanto, também em um Storyboard, ocorrerão no próximo tique do mecanismo de temporização, que acontecerá pouco antes da próxima renderização. Por exemplo, se você usar o método Seek para ir para outro ponto em uma animação, o valor da propriedade não será alterado instantaneamente; o valor será modificado no próximo ciclo do mecanismo de tempo.

O exemplo a seguir mostra como aplicar e controlar animações usando os métodos interativos da Storyboard classe.

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

namespace SDKSample
{

    public class ControllableStoryboardExample : Page
    {
        private Storyboard myStoryboard;

        public ControllableStoryboardExample()
        {

            // Create a name scope for the page.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Namespace SDKSample

    Public Class ControllableStoryboardExample
        Inherits Page
        Private myStoryboard As Storyboard

        Public Sub New()

            ' Create a name scope for the page.

            NameScope.SetNameScope(Me, New NameScope())

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

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

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

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

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

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


        End Sub

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

        End Sub

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

        End Sub

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

        End Sub

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

        End Sub

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

        End Sub

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

        End Sub

    End Class

End Namespace

Animar em um estilo

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

  • Você não especifica um TargetName; o Storyboard sempre direciona ao elemento ao qual o Style é aplicado. Para direcionar Freezable objetos, você deve usar o direcionamento indireto. Para obter mais informações sobre direcionamento indireto, consulte a seção Direcionamento Indireto .

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

  • Você não pode usar referências dinâmicas de recurso ou expressões de associação de dados para definir valores de propriedade de Storyboard ou de animação. Isso ocorre porque tudo dentro de um Style deve ser thread-safe, e o sistema de cronometragem deve FreezeStoryboard objetos para torná-los thread-safe. Um Storyboard não pode ser congelado se ele ou suas timelines aninhadas contiverem referências dinâmicas de recurso ou expressões de vínculo de dados. Para obter mais informações sobre congelamento e outros Freezable recursos, consulte a visão geral de objetos do Freezable.

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

Para obter um exemplo que mostra como definir um storyboard em estilo, consulte o exemplo Animar em um estilo.

Animar em um ControlTemplate

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

  • O TargetName pode referir-se somente a objetos filhos do ControlTemplate. Se TargetName não for especificado, a animação se destina ao elemento ao qual o ControlTemplate é aplicado.

  • O SourceName para um EventTrigger ou um Trigger só pode se referir a objetos filho do ControlTemplate.

  • Você não pode usar referências dinâmicas de recurso ou expressões de associação de dados para definir valores de propriedade de Storyboard ou de animação. Isso ocorre porque tudo dentro de um ControlTemplate deve ser thread-safe, e o sistema de cronometragem deve FreezeStoryboard objetos para torná-los thread-safe. Um Storyboard não pode ser congelado se ele ou suas timelines aninhadas contiverem referências dinâmicas de recurso ou expressões de vínculo de dados. Para obter mais informações sobre congelamento e outros Freezable recursos, consulte a visão geral de objetos do Freezable.

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

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

Realizar animação quando um valor de propriedade é alterado

Em estilos e modelos de controle, você pode usar objetos Trigger para iniciar um storyboard quando uma propriedade é alterada. Para obter exemplos, consulte Disparar uma animação quando um valor de propriedade for alterado e animar em um ControlTemplate.

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

Consulte também