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 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 , 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 de tempo complexos. 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 Os objetos 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 storyboarding é um recurso de nível de estrutura, o objeto deve pertencer ao NameScope de um FrameworkElement ou a um FrameworkContentElement.

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

No entanto, você não pôde usar um para animar um que não registrou seu nome com um ou , ou não foi usado para definir uma propriedade de um StoryboardFrameworkElementFrameworkElementSolidColorBrush ou .FrameworkContentElementFrameworkContentElement

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 filho 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 a seus destinos, comece a usar uma ação de gatilho Storyboard ou um método. Em XAML, você usa um objeto com um BeginStoryboardEventTrigger, Triggerou DataTrigger. No código, você também pode usar o Begin método.

A tabela a seguir mostra os diferentes locais onde 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 Yes Animar uma propriedade usando um storyboard
BeginStoryboard e um imóvel Trigger Não Sim Sim Yes Disparar uma animação quando o valor de uma propriedade é alterado
BeginStoryboard e um imóvel MultiTrigger Não Sim Sim Yes Exemplo de classe MultiTrigger
BeginStoryboard e um DataTrigger Não Sim Sim Yes Como disparar uma animação quando dados são alterados
BeginStoryboard e um MultiDataTrigger Não Sim Sim Yes Exemplo de classe MultiDataTrigger
Método Begin Sim No No Não Animar uma propriedade usando um storyboard

O exemplo a seguir usa um para animar o de um elemento e o Width de um RectangleSolidColorBrushStoryboard usado para pintar esse Rectangle.Color

<!-- 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 anexadas e TargetProperty com TargetName 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 propriedade para vincular diretamente a Target 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 um ou a em XAML é diferente de atribuir um nome a FrameworkContentElement um FrameworkElementFreezable objeto.

Os elementos de estrutura são aquelas classes que herdam da FrameworkElement classe. Exemplos de elementos de estrutura incluem Window, , ButtonDockPanele 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 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 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 método para registrar o nome do elemento com o elemento para o RegisterName qual você criou um NameScopearquivo .

O exemplo a seguir, retirado do exemplo anterior, atribui ao 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));

Freezable tipos são aquelas classes que herdam da Freezable classe. Exemplos de Freezable incluir SolidColorBrush, RotateTransforme GradientStop.

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

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 propriedade for omitida, a TargetName animação terá como alvo o elemento no qual ela está definida ou, no caso de estilos, o elemento styled.

Às vezes, um nome não pode ser atribuído a um Freezable objeto. Por exemplo, se um for declarado como um recurso ou usado para definir um valor de propriedade em um estilo, ele não poderá receber um Freezable 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 um 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 Freezable estilo. Nesses casos, mesmo que você não possa direcioná-lo diretamente, você ainda pode animar o Freezable objeto. Em vez de definir a propriedade com o nome do , você dá a TargetName ela o nome do Freezableelemento ao qual o Freezable "pertence". Por exemplo, um usado para definir o Fill de um SolidColorBrush elemento 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 elemento de conteúdo de estrutura que foi Freezable usado para definir e termina com a propriedade a Freezable 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 for 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 de um determinado botão foi definido com um e tentar animar sua Cor, quando na verdade um SolidColorBrushLinearGradientBrush foi usado para definir o Background Plano de Fundo do botão. Nesses casos, nenhuma exceção é lançada; A animação não consegue ter 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
ElementPropertyName.FreezablePropertyName

Where

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

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

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 Freezable propriedade do destino para. Pense nisso como uma cadeia de propriedades que conecta o Freezable ao FrameworkElement objeto.

A seguir está um exemplo de uma cadeia de propriedades de dependência que tem como alvo o de um usado para definir o ColorFill de um SolidColorBrush elemento retângulo.

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

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

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

Where

O exemplo a seguir mostra o que acompanharia o PathPathParameters 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 de um usado para definir o ColorFill de um SolidColorBrush 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 propriedade da RotateTransform, a Angle segunda transformação no 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 contido em um RotateTransformTransformGrouparquivo .

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 um começando com um FreezableFrameworkElement ou FrameworkContentElement e criando uma cadeia de propriedades para uma Freezable subpropriedade. Você também pode usar um Freezable como ponto de partida e direcionar indiretamente uma de suas Freezable subpropriedades. Uma restrição adicional se aplica ao usar um Freezable como ponto de partida para direcionamento indireto: o início Freezable e todos entre Freezable ele e a subpropriedade indiretamente visada 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 disparo. 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 tornado 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 tomadas em um , e, portanto, também em um ClockStoryboard ocorrerão no próximo tick do mecanismo de temporização, o que acontecerá pouco antes da próxima renderização. Por exemplo, se você usar o método para saltar para outro ponto em uma animação, o valor da propriedade não será alterado instantaneamente, em vez disso, o Seek valor será alterado no próximo tick 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 . Animar com um em um é semelhante ao uso de um StoryboardStyleStoryboard em outro lugar, com as três exceções a seguir:

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

  • Não é possível especificar um para um ou um SourceNameEventTriggerTriggerarquivo .

  • Não é possível usar referências de recursos dinâmicos ou expressões de vinculação de dados para definir Storyboard ou animar valores de propriedade. Isso porque tudo dentro de um Style deve ser thread-safe, e o sistema de temporização deve FreezeStoryboard objetar para torná-los thread-safe. Um Storyboard não pode ser congelado se ele ou suas linhas do tempo filho contiverem referências dinâmicas de recursos 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 para Storyboard eventos ou 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 . Animar com um em um é semelhante ao uso de um StoryboardControlTemplateStoryboard em outro lugar, com as duas exceções a seguir:

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

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

  • Não é possível usar referências de recursos dinâmicos ou expressões de vinculação de dados para definir Storyboard ou animar valores de propriedade. Isso porque tudo dentro de um ControlTemplate deve ser thread-safe, e o sistema de temporização deve FreezeStoryboard objetar para torná-los thread-safe. Um Storyboard não pode ser congelado se ele ou suas linhas do tempo filho contiverem referências dinâmicas de recursos 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 para Storyboard eventos ou animação.

Para obter um exemplo mostrando como definir um storyboard em um ControlTemplate, consulte o exemplo Animate in a 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 animações acionadas por EventTrigger método.

Confira também