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 esse 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 usar propriedades anexadas. Para obter mais informações sobre as propriedades anexadas, consulte Visão geral das 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 a propriedades. As linhas do tempo do contêiner derivam da TimelineGroup classe e incluem ParallelTimeline e Storyboard.

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

  • Aumenta e muda de cor quando o usuário o seleciona.

  • Diminui e, em seguida, aumenta novamente para seu tamanho original quando recebe um clique.

  • Diminui e esmaece até uma opacidade de 50% quando é desabilitado.

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

Onde você pode usar um storyboard

A 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 a Visão geral da animação). No entanto, como o NameScope storyboard é um recurso no nível da estrutura, o objeto deve pertencer ao de um FrameworkElement ou a um FrameworkContentElement.

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

No entanto, você não pode usar a 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 linhas do tempo filhas do Storyboard. A Storyboard classe fornece as Storyboard.TargetName propriedades e Storyboard.TargetProperty anexadas. Você pode definir essas propriedades em uma animação para especificar seu objeto de destino e sua propriedade.

Para aplicar animações aos seus destinos, você começa a Storyboard usar uma ação de gatilho ou um método. Em XAML, você usa um BeginStoryboard objeto com um EventTrigger, Trigger, ou 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 é suportada: por instância, estilo, modelo de controle e modelo de dados. "Por instância" se refere à 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 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 o valor de uma propriedade é alterado
BeginStoryboard e uma propriedade MultiTrigger Não Sim Sim Sim Exemplo de classe MultiTrigger
BeginStoryboard e um DataTrigger Não Sim Sim Sim Como disparar uma animação quando dados são alterados
BeginStoryboard e um MultiDataTrigger Não Sim Sim Sim Exemplo de classe MultiDataTrigger
Beginmétodo Sim Não No No Animar uma propriedade usando um storyboard

O exemplo a seguir usa a Storyboard para animar o Width de um Rectangle 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 e TargetProperty anexadas TargetName com mais detalhes.

Definindo como destino elementos de estrutura, elementos de conteúdo de estrutura e congeláveis

Na seção anterior, mencionamos que, para uma animação encontrar seu destino, ela deve saber o nome do destino e a propriedade a ser animada. Especificar a propriedade a ser animada é simples: basta definir TargetProperty com o nome da propriedade a ser animada. Você especifica o nome do objeto cuja propriedade deseja animar definindo a Storyboard.TargetName propriedade na animação.

Cuidado

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

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

Os elementos de estrutura são aquelas classes que herdam da FrameworkElement classe. Exemplos de elementos de estrutura incluem Window, DockPanel, Buttone Rectangle. Basicamente, todas as janelas, todos os painéis e todos os controles são elementos. Os elementos de conteúdo da estrutura são aquelas classes que herdam da FrameworkContentElement classe. Exemplos de elementos de conteúdo de estrutura incluem FlowDocument e Paragraph. Se você não tiver certeza se um tipo é um elemento de estrutura ou um elemento de conteúdo de estrutura, verifique se ele tem uma propriedade Name. Se isso acontecer, provavelmente, ele será um elemento de estrutura ou um elemento de conteúdo de estrutura. Para ter certeza, confira a seção Hierarquia de herança da página de seu tipo.

Para habilitar o direcionamento de um elemento de estrutura ou de um elemento de conteúdo de estrutura em XAML, defina sua Name propriedade. 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, retirado do exemplo anterior, atribui o nome MyRectangle a , Rectangleum 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));

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

Para habilitar o direcionamento de uma Freezable animação em XAML, use a diretiva x:Name para atribuir um nome a ela. No código, você usa o RegisterName método para registrar seu nome com o 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 o destino 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));

Storyboard Os objetos usam escopos de nome para resolver a TargetName propriedade. Para obter mais informações sobre escopos de nome no WPF, consulte Escopos de nome XAML no WPF. Se a TargetName propriedade for omitida, a animação terá como destino o elemento no qual ela está 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 a 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 definido como destino diretamente – mas ele pode ser definido como destino indiretamente. As próximas seções descrevem como usar o direcionamento indireto.

Direcionamento indireto

Há momentos em que a Freezable não pode ser direcionado diretamente por uma animação, como quando o é declarado Freezable como um recurso ou usado para definir um valor de propriedade em um estilo. Nesses casos, mesmo que você não possa direcioná-lo diretamente, ainda é possível animar o Freezable objeto. Em vez de definir a TargetName propriedade com o nome do Freezable, você dá a ela o nome do elemento ao qual o Freezable "pertence". Por exemplo, um SolidColorBrush usado para definir o Fill de um elemento de retângulo pertence a esse retângulo. Para animar o pincel, você definiria a animação TargetProperty com uma cadeia de propriedades que começa na propriedade do elemento de estrutura ou do elemento de conteúdo de estrutura que foi Freezable usado para definir e termina com a Freezable propriedade 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 objetos congeláveis.

Observe também que, ao usar o direcionamento indireto de propriedade, é possível definir como destino objetos inexistentes. Por exemplo, você pode supor que o Background de um botão específico foi definido com a SolidColorBrush e tentar animar sua cor, quando na verdade a LinearGradientBrush foi usado para definir o plano de fundo do botão. Nesses casos, nenhuma exceção é lançada; A animação não tem um efeito visível porque LinearGradientBrush não reage às alterações na Color propriedade.

As próximas seções descrevem a sintaxe de direcionamento indireto de propriedade mais detalhadamente.

Definindo indiretamente como destino uma propriedade de um congelável em XAML

Para direcionar uma propriedade de um freezable em XAML, use a sintaxe a seguir.

Sintaxe de propriedade
Nome_da_propriedade_do_ . elemento Nome_da_propriedade_do_elemento Freezable_Property

Onde

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

  • FreezablePropertyName é a propriedade do Freezable modo para animar.

O código a seguir mostra como animar o Color de um SolidColorBrush usado para definir o Fill de um elemento de 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 ter como destino um congelável contido em uma coleção ou matriz.

Para definir um congelável como destino contido em uma coleção, use a sintaxe de caminho a seguir.

Sintaxe de path
ElementPropertyName .Children[ CollectionIndex ]. FreezablePropertyName

Em que 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 Angle RotateTransform propriedade do 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>  

Definindo indiretamente como destino uma propriedade de um congelável no código

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

Para criar PathParameterso , crie uma matriz do tipo DependencyProperty que contém uma lista de campos de identificador de propriedade 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 do Freezable destino to. Pense nisso como uma cadeia de propriedades que conecta o Freezable ao FrameworkElement objeto.

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 de um elemento de retângulo.

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

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

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

Onde

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

  • FreezablePropertyArrayIndex é o DependencyProperty índice da matriz que contém o identificador da propriedade a ser direcionada.

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

Às vezes, você precisa ter como destino um congelável 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 a seguir.

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

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

Para direcionar a Angle RotateTransformpropriedade da , a segunda transformação na 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);

Definindo indiretamente como destino um congelável como o ponto de partida

As seções anteriores descreveram como direcionar indiretamente a Freezable começando com um FrameworkElement ou FrameworkContentElement e criando uma cadeia de propriedades para uma Freezable subpropriedade. Você também pode usar a Freezable como ponto de partida e direcionar indiretamente uma de suas Freezable subpropriedades. Uma restrição adicional se aplica ao usar a Freezable como ponto de partida para a segmentação indireta: o inicial Freezable e o cada Freezable entre ele e a subpropriedade indiretamente direcionada não devem ser congelados.

Controlando um storyboard de forma interativa no 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 que eles animam e inicia o storyboard. (Para obter detalhes sobre esse processo, consulte o Visão geral do sistema de animação e temporização.) Se você der um BeginStoryboard nome especificando sua Name propriedade, você o tornará um storyboard controlável. Você poderá então controlar o storyboard de forma interativa depois que ele for iniciado. Veja a seguir uma lista de ações de storyboard controlável usadas com gatilhos de evento para controlar um storyboard.

No exemplo a seguir, as ações de storyboard controlável são usadas para controlar um storyboard de forma interativa.

<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 um storyboard de forma interativa usando um 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 que um Storyboard seja interativo no código, você deve usar a sobrecarga apropriada do método do Begin storyboard e especificar true para torná-lo 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 depois que ele foi iniciado:

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 Clocke, 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 Seek método para pular para outro ponto em uma animação, o valor da propriedade não será alterado instantaneamente, em vez disso, o valor será alterado no próximo tique do mecanismo de temporização.

O exemplo a seguir mostra como aplicar e controlar animações usando os Storyboard métodos interativos da 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 Stylearquivo . A animação com um Storyboard em a Style é semelhante ao uso de a Storyboard em outro lugar, com as três exceções a seguir:

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

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

  • Você não pode usar referências de recursos dinâmicos ou expressões de associação de dados para definir Storyboard valores de propriedade de animação. Isso ocorre porque tudo dentro de um Style deve ser thread-safe, e o sistema de temporização deve FreezeStoryboard se opor para torná-los thread-safe. A Storyboard não pode ser congelado se ele ou suas linhas do tempo filhas contiverem referências de recursos dinâmicos ou expressões de vinculação de dados. Para obter mais informações sobre congelamento e outros Freezable recursos, consulte a Visão geral de objetos congeláveis.

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

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

Animar em um ControlTemplate

Você pode usar Storyboard objetos para definir animações em um ControlTemplatearquivo . A animação com um Storyboard em a ControlTemplate é semelhante a usar um Storyboard em outro lugar, com as duas exceções a seguir:

  • O TargetName pode se referir apenas a objetos filho do ControlTemplate. Se TargetName não for especificado, a animação terá como destino o elemento ao qual o ControlTemplate é aplicado.

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

  • Você não pode usar referências de recursos dinâmicos ou expressões de associação de dados para definir Storyboard valores de propriedade de animação. Isso ocorre porque tudo dentro de um ControlTemplate deve ser thread-safe, e o sistema de temporização deve FreezeStoryboard se opor para torná-los thread-safe. A Storyboard não pode ser congelado se ele ou suas linhas do tempo filhas contiverem referências de recursos dinâmicos ou expressões de vinculação de dados. Para obter mais informações sobre congelamento e outros Freezable recursos, consulte a Visão geral de objetos congeláveis.

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

Para obter um exemplo que mostra como definir um storyboard em um ControlTemplate, consulte o exemplo Animate em um ControlTemplate .

Animar quando um valor da 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 o valor de uma propriedade é alterado e Animar em um ControlTemplate.

As animações aplicadas por objetos de propriedade Trigger se comportam de maneira mais complexa do que EventTrigger as 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 acionadas por método.

Confira também