Animações de quadro chave e animações com função de easingKey-frame animations and easing function animations

Animações de quadro chave lineares, animações de quadro chave com um KeySpline ou funções de easing são três técnicas diferentes para basicamente o mesmo cenário: criar uma animação de storyboard um pouco mais complexa e que usa um comportamento de animação não linear de um estado inicial até um estado final.Linear key-frame animations, key-frame animations with a KeySpline value, or easing functions are three different techniques for approximately the same scenario: creating a storyboarded animation that's a bit more complex, and that uses a nonlinear animation behavior from a starting state to an end state.

Pré-requisitosPrerequisites

Leia o tópico Animações de storyboard.Make sure you've read the Storyboarded animations topic. Este tópico faz referência aos conceitos de animação que foram explicados em Animações de storyboard e não os descreverá novamente.This topic builds on the animation concepts that were explained in Storyboarded animations and won't go over them again. Por exemplo, Animações de storyboard descreve como direcionar animações, storyboards como recursos, os valores da propriedade Timeline como Duration, FillBehavior etc.For example, Storyboarded animations describes how to target animations, storyboards as resources, the Timeline property values such as Duration, FillBehavior, and so on.

Animando usando animações de quadro chaveAnimating using key-frame animations

As animações de quadro chave permitem mais de um valor de destino, que é atingido em um ponto ao longo da linha do tempo da animação.Key-frame animations permit more than one target value that is reached at a point along the animation timeline. Em outras palavras, cada quadro chave pode especificar um valor intermediário diferente, e o último quadro chave atingido é o valor de animação final.In other words, each key frame can specify a different intermediate value, and the last key frame reached is the final animation value. Especificando vários valores a serem animados, você pode criar animações mais complexas.By specifying multiple values to animate, you can make more complex animations. As animações de quadro chave também permitem uma lógica de interpolação diferente, sendo cada uma implementada como uma subclasse KeyFrame diferente por tipo de animação.Key-frame animations also enable different interpolation logic, which are each implemented as a different KeyFrame subclass per animation type. Mais especificamente, cada tipo de animação de quadro chave tem uma variação de Discrete, Linear, Spline and Easing de sua classe KeyFrame para a especificação de seus quadros chave.Specifically, each key-frame animation type has a Discrete, Linear, Spline and Easing variation of its KeyFrame class for specifying its key frames. Por exemplo, para especificar uma animação que direciona um Double e usa quadros chave, você pode declarar quadros chave com DiscreteDoubleKeyFrame, LinearDoubleKeyFrame, SplineDoubleKeyFrame e EasingDoubleKeyFrame.For example, to specify an animation that targets a Double and uses key frames, you could declare key frames with DiscreteDoubleKeyFrame, LinearDoubleKeyFrame, SplineDoubleKeyFrame, and EasingDoubleKeyFrame. Você pode usar qualquer um e todos esses tipos em uma única coleção de KeyFrames para alterar a interpolação sempre que um novo quadro chave for atingido.You can use any and all of these types within a single KeyFrames collection, to change the interpolation each time a new key frame is reached.

Para o comportamento de interpolação, cada quadro chave controla a interpolação até que o tempo de seu KeyTime seja atingido.For interpolation behavior, each key frame controls the interpolation until its KeyTime time is reached. Seu Value também é atingido nesse momento.Its Value is reached at that time also. Se houver mais quadros chaves depois, o valor então se torna o valor inicial para o próximo quadro chave em uma sequência.If there are more key frames beyond, the value then becomes the starting value for the next key frame in a sequence.

No início da animação, se nenhum quadro chave com um KeyTime de "0:0:0" existir, o valor inicial será o valor não animado da propriedade.At the start of the animation, if no key frame with KeyTime of "0:0:0" exists, the starting value is whatever the non-animated value of the property is. Isso é semelhante a como um do / para / por animação age se não houver de.This is similar to how a From/To/By animation acts if there is no From.

A duração de uma animação de quadro chave é implicitamente a duração equivalente ao valor KeyTime mais alto definido em qualquer um de seus quadros chave.The duration of a key-frame animation is implicitly the duration equal to the highest KeyTime value set in any of its key frames. Você pode definir um Duration explícito se desejar, mas tome cuidado para que ele não seja menor do que um KeyTime em seus próprios quadros chave, caso contrário, parte da animação será cortada.You can set an explicit Duration if you want, but be careful it's not shorter than a KeyTime in your own key frames or you'll cut off part of the animation.

Além de Duration, você pode definir todas as propriedades baseadas em Timeline em uma animação de quadro chave, da mesma maneira que é possível com uma animação From/To/By porque as classes de animação de quadro chave também são derivadas de Timeline.In addition to Duration, you can set all the Timeline based properties on a key-frame animation, like you can with a From/To/By animation, because the key-frame animation classes also derive from Timeline. Eles são:These are:

  • AutoReverse: depois que o último quadro chave é atingido, os quadros são repetidos na ordem inversa a partir do final.AutoReverse: once the last key frame is reached, the frames are repeated in reverse order from the end. Isso duplica a duração aparente da animação.This doubles the apparent duration of the animation.
  • BeginTime: atrasa o início da animação.BeginTime: delays the start of the animation. A linha do tempo dos valores KeyTime nos quadros não começa a contar até que BeginTime seja atingido, assim, não há risco de que os quadros sejam cortadosThe timeline for the KeyTime values in the frames doesn't start counting until BeginTime is reached, so there's no risk of cutting off frames
  • FillBehavior: controla o que acontece quando o último quadro chave é atingido.FillBehavior: controls what happens when the last key frame is reached. FillBehavior não tem efeito sobre quadros chave intermediários.FillBehavior has no effect on any intermediate key frames.
  • RepeatBehavior:RepeatBehavior:
    • Se definidos como Forever, os quadros chave e sua linha do tempo serão repetidos infinitamente.If set to Forever, then the key frames and their timeline repeat infinitely.
    • Se definida como uma contagem de iteração, a linha do tempo será repetida várias vezes.If set to an iteration count, the timeline repeats that many times.
    • Se definida como Duration, a linha do tempo será repetida até que esse tempo seja atingido.If set to a Duration, the timeline repeats until that time is reached. Isso pode truncar a animação no meio da sequência de quadros chave se não for um fator inteiro da duração implícita da linha do tempo.This might truncate the animation part way through the key frame sequence, if it's not an integer factor of the timeline's implicit duration.
  • SpeedRatio (não usada com frequência)SpeedRatio (not commonly used)

Quadros chave linearesLinear key frames

Quadros chave lineares resultam em uma interpolação linear mais simples do valor até que o KeyTime do quadro seja atingido.Linear key frames result in a simple linear interpolation of the value until the frame's KeyTime is reached. Esse comportamento de interpolação é o mais semelhante ao da mais simples das / To / By animações descritas no tópico animações storyboards .This interpolation behavior is the most similar to the simpler From/To/By animations described in the Storyboarded animations topic.

Consulte a seguir como usar uma animação de quadro chave para redimensionar a altura de renderização de um retângulo usando quadros chave linears.Here's how to use a key-frame animation to scale the render height of a rectangle, using linear key frames. Esse exemplo executa uma animação em que a altura do retângulo aumenta ligeiramente de maneira linear nos primeiros quatro segundos e depois e redimensionada rapidamente nos últimos dois segundos até que o retângulo tenha o dobro da altura inicial.This example runs an animation where the height of the rectangle increases slightly and linearly for the first 4 seconds, then scales rapidly for the last second until the rectangle is double the starting height.

<StackPanel>
    <StackPanel.Resources>
        <Storyboard x:Name="myStoryboard">
            <DoubleAnimationUsingKeyFrames
              Storyboard.TargetName="myRectangle"
              Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
                <LinearDoubleKeyFrame Value="1" KeyTime="0:0:0"/>
                <LinearDoubleKeyFrame Value="1.2" KeyTime="0:0:4"/>
                <LinearDoubleKeyFrame Value="2" KeyTime="0:0:5"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </StackPanel.Resources>
</StackPanel>

Quadros chave separadosDiscrete key frames

Os quadros chave separados não usam interpolação.Discrete key frames don't use any interpolation at all. Quando um KeyTime é atingido, o novo Value é simplesmente aplicado.When a KeyTime is reached, the new Value is simply applied. Dependendo de qual propriedade da interface do usuário estiver sendo animada, isso geralmente produz uma animação que parece "saltar".Depending on which UI property is being animated, this often produces an animation that appears to "jump". Certifique-se de que esse é o comportamento estético realmente desejado.Be certain that this is the aesthetic behavior that you really want. Você pode atenuar os saltos aparentes aumentando o número de quadros chave declarados, mas, se desejar uma animação suave, é melhor usar quadros chave lineares ou de spline.You can minimize the apparent jumps by increasing the number of key frames you declare, but if a smooth animation is your goal, you might be better off using linear or spline key frames instead.

Observação

Quadros chave discretos são a única maneira de animar um valor que não é do tipo Double, Point e Color, com um DiscreteObjectKeyFrame.Discrete key frames are the only way to animate a value that isn't of type Double, Point, and Color, with a DiscreteObjectKeyFrame. Abordaremos isso em mais detalhes adiante neste tópico.We'll discuss this in more detail later in this topic.

Quadros chave de splineSpline key frames

Um quadro chave de spline cria uma transição variável entre valores de acordo com o valor da propriedade KeySpline.A spline key frame creates a variable transition between values according to the value of the KeySpline property. Essa propriedade especifica o primeiro e o segundo ponto de controle de uma curva de Bézier, que descreve a aceleração da animação.This property specifies the first and second control points of a Bezier curve, which describes the acceleration of the animation. Basicamente, um KeySpline define uma relação de função ao longo do tempo em que o gráfico função-tempo é a forma dessa curva de Bézier.Basically, a KeySpline defines a function-over-time relationship where the function-time graph is the shape of that Bezier curve. Geralmente, você especifica um valor KeySpline em uma cadeia de caracteres de atributo XAML abreviada que tem quatro valores Double separados por espaços ou vírgulas.You typically specify a KeySpline value in a XAML shorthand attribute string that has four Double values separated by spaces or commas. Esses valores são pares "X, Y" para dois pontos de controle da curva de Bézier.These values are "X,Y" pairs for two control points of the Bezier curve. "X" é o tempo e "Y" é o modificador de função para o valor."X" is time and "Y" is the function modifier to the value. Cada valor deve estar sempre entre 0 e 1.Each value should always be between 0 and 1 inclusive. Sem modificação do ponto de controle para um KeySpline, a linha reta de 0,0 a 1,1 é a representação de uma função ao longo do tempo para uma interpolação linear.Without control point modification to a KeySpline, the straight line from 0,0 to 1,1 is the representation of a function over time for a linear interpolation. Seus pontos de controle alteram a forma dessa curva e, assim, o comportamento da função ao longo do tempo da animação de spline.Your control points change the shape of that curve and thus the behavior of the function over time for the spline animation. Provavelmente, é melhor conferir isso visualmente em um gráfico.It's probably best to see this visually as a graph. Você pode executar o Exemplo de visualizador de spline chave do Silverlight em um navegador para ver como os pontos de controle modificam a curva e como uma animação de exemplo é executada quando é usada como um valor KeySplineYou can run the Silverlight key-spline visualizer sample in a browser to see how the control points modify the curve and how a sample animation runs when using it as a KeySpline value.

Este próximo exemplo mostra três quadros chave diferentes aplicados a uma animação, em que o último é uma animação de spline chave para um valor Double (SplineDoubleKeyFrame).This next example shows three different key frames applied to an animation, with the last one being a key spline animation for a Double value (SplineDoubleKeyFrame). Observe a cadeia de caracteres "0.6,0.0 0.9,0.00" aplicada a KeySpline.Note the string "0.6,0.0 0.9,0.00" applied for KeySpline. Isso gera uma curva em que a animação parece ser executada devagar inicialmente, mas depois ela rapidamente atinge o valor logo antes de KeyTime ser atingido.This produces a curve where the animation appears to run slowly at first but then rapidly reaches the value just before the KeyTime is reached.

<Storyboard x:Name="myStoryboard">
    <!-- Animate the TranslateTransform's X property
        from 0 to 350, then 50,
        then 200 over 10 seconds. -->
    <DoubleAnimationUsingKeyFrames
        Storyboard.TargetName="MyAnimatedTranslateTransform"
        Storyboard.TargetProperty="X"
        Duration="0:0:10" EnableDependentAnimation="True">

        <!-- Using a LinearDoubleKeyFrame, the rectangle moves 
            steadily from its starting position to 500 over 
            the first 3 seconds.  -->
        <LinearDoubleKeyFrame Value="500" KeyTime="0:0:3"/>

        <!-- Using a DiscreteDoubleKeyFrame, the rectangle suddenly 
            appears at 400 after the fourth second of the animation. -->
        <DiscreteDoubleKeyFrame Value="400" KeyTime="0:0:4"/>

        <!-- Using a SplineDoubleKeyFrame, the rectangle moves 
            back to its starting point. The
            animation starts out slowly at first and then speeds up. 
            This KeyFrame ends after the 6th second. -->
        <SplineDoubleKeyFrame KeySpline="0.6,0.0 0.9,0.00" Value="0" KeyTime="0:0:6"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

Quadros chave de easingEasing key frames

Um quadro chave de easing é um quadro chave em que a interpolação está sendo aplicada e a função ao longo do tempo da interpolação é controlada por várias fórmulas matemáticas predefinidas.An easing key frame is a key frame where interpolation is being applied, and the function over time of the interpolation is controlled by several pre-defined mathematical formulas. Na realidade, você pode gerar, com um quadro chave de spline, quase o mesmo resultado obtido com alguns tipos de função de easing, mas também há algumas funções de easing, como BackEase, que você não pode reproduzir com um spline.You can actually produce much the same result with a spline key frame as you can with some of the easing function types, but there are also some easing functions, such as BackEase, that you can't reproduce with a spline.

Para aplicar uma função de easing a um quadro chave de easing, você define a propriedade EasingFunction como um elemento de propriedade no XAML para esse quadro chave.To apply an easing function to an easing key frame, you set the EasingFunction property as a property element in XAML for that key frame. Para o valor, especifique um elemento de objeto para um dos tipos de função de easing.For the value, specify an object element for one of the easing function types.

Esse exemplo aplica um CubicEase e um BounceEase como quadros chave sucessivos a um DoubleAnimation para criar um efeito de salto.This example applies a CubicEase and then a BounceEase as successive key frames to a DoubleAnimation to create a bouncing effect.

<Storyboard x:Name="myStoryboard">
    <DoubleAnimationUsingKeyFrames Duration="0:0:10"
        Storyboard.TargetProperty="Height"
        Storyboard.TargetName="myEllipse">

        <!-- This keyframe animates the ellipse up to the crest 
            where it slows down and stops. -->
        <EasingDoubleKeyFrame Value="-300" KeyTime="00:00:02">
            <EasingDoubleKeyFrame.EasingFunction>
                <CubicEase/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>

        <!-- This keyframe animates the ellipse back down and makes
            it bounce. -->
        <EasingDoubleKeyFrame Value="0" KeyTime="00:00:06">
            <EasingDoubleKeyFrame.EasingFunction>
                <BounceEase Bounces="5"/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

Este é apenas um exemplo de função de easing.This is just one easing function example. Abordaremos mais na próxima seção.We'll cover more in the next section.

Funções de easingEasing functions

As funções easing permitem aplicar fórmulas matemáticas personalizadas às suas animações.Easing functions allow you to apply custom mathematical formulas to your animations. As operações matemáticas geralmente são úteis para produzir animações que simulam a física real em um sistema de coordenadas 2D.Mathematical operations are often useful to produce animations that simulate real-world physics in a 2-D coordinate system. Por exemplo, talvez você queira que um objeto ricocheteie de modo realista ou comporte-se como se estivesse em uma mola.For example, you may want an object to realistically bounce or behave as though it were on a spring. Você pode usar o quadro-chave ou até mesmo de / To / By animações para aproximar esses efeitos, mas isso levaria uma quantidade significativa de trabalho e a animação seria menos precisa do que usar uma fórmula matemática.You could use key frame or even From/To/By animations to approximate these effects but it would take a significant amount of work and the animation would be less accurate than using a mathematical formula.

As funções de easing podem ser aplicadas a animações de três maneiras:Easing functions can be applied to animations in three ways:

Consulte a seguir uma lista das funções de easing:Here is a list of the easing functions:

  • BackEase: retrai levemente o movimento de uma animação antes que ela comece a se animar no caminho indicado.BackEase: Retracts the motion of an animation slightly before it begins to animate in the path indicated.
  • BounceEase: cria um efeito de saltos.BounceEase: Creates a bouncing effect.
  • CircleEase: cria uma animação que é acelerada ou desacelerada usando uma função circular.CircleEase: Creates an animation that accelerates or decelerates using a circular function.
  • CubicEase: cria uma animação que é acelerada ou desacelerada usando a fórmula f(t) = t3.CubicEase: Creates an animation that accelerates or decelerates using the formula f(t) = t3.
  • ElasticEase: cria uma animação que parece uma mola oscilando até descansar.ElasticEase: Creates an animation that resembles a spring oscillating back and forth until it comes to rest.
  • ExponentialEase: cria uma animação que é acelerada ou desacelerada usando uma fórmula exponencial.ExponentialEase: Creates an animation that accelerates or decelerates using an exponential formula.
  • PowerEase: cria uma animação que é acelerada ou desacelerada usando a fórmula f(t) = tp, em que p é igual à propriedade Power.PowerEase: Creates an animation that accelerates or decelerates using the formula f(t) = tp where p is equal to the Power property.
  • QuadraticEase: cria uma animação que é acelerada ou desacelerada usando a fórmula f(t) = t2.QuadraticEase: Creates an animation that accelerates or decelerates using the formula f(t) = t2.
  • QuarticEase: cria uma animação que é acelerada ou desacelerada usando a fórmula f(t) = t4.QuarticEase: Creates an animation that accelerates or decelerates using the formula f(t) = t4.
  • QuinticEase: cria uma animação que é acelerada ou desacelerada usando a fórmula f(t) = t5.QuinticEase: Create an animation that accelerates or decelerates using the formula f(t) = t5.
  • SineEase: cria uma animação que é acelerada ou desacelerada usando uma fórmula seno.SineEase: Creates an animation that accelerates or decelerates using a sine formula.

Algumas das funções de easing têm suas próprias propriedades.Some of the easing functions have their own properties. Por exemplo, BounceEase tem duas propriedades Bounces e Bounciness que modificam o comportamento da função ao longo do tempo desse BounceEase específico.For example, BounceEase has two properties Bounces and Bounciness that modify the function-over-time behavior of that particular BounceEase. Outras funções de easing, como CubicEase não têm propriedades adicionais além da propriedade EasingMode compartilhada por todas as funções de easeing e sempre produzem o mesmo comportamento de função ao longo do tempo.Other easing functions such as CubicEase don't have properties other than the EasingMode property that all easing functions share, and always produce the same function-over-time behavior.

Algumas dessas funções de easing têm um pouco de sobreposição, dependendo de como você define as propriedades nas funções de easing que têm propriedades.Some of these easing functions have a bit of overlap, depending on how you set properties on the easing functions that have properties. Por exemplo, QuadraticEase é exatamente o mesmo que um PowerEase com Power igual a 2.For example, QuadraticEase is exactly the same as a PowerEase with Power equal to 2. Além disso, CircleEase é basicamente um ExponentialEase de valor padrão.And CircleEase is basically a default-value ExponentialEase.

A função de easing BackEase é exclusiva porque pode alterar o valor fora do intervalo normal definido por From/To ou valores de quadros chave.The BackEase easing function is unique because it can change the value outside of the normal range as set by From/To or values of key frames. Ele inicia a animação alterando o valor na direção oposta, conforme esperado de um normal de / para comportamento, retorna novamente para o valor de ou inicial e, em seguida, executa a animação normalmente.It starts the animation by changing the value in the opposite direction as would be expected from a normal From/To behavior, goes back to the From or starting value again, and then runs the animation as normal.

Em um exemplo anterior, mostramos como declarar uma função de easing para uma animação de quadro chave.In an earlier example, we showed how to declare an easing function for a key-frame animation. Este próximo exemplo aplica uma função de atenuação a uma animação de / a a / por .This next sample applies an easing function to a From/To/By animation.

<StackPanel x:Name="LayoutRoot" Background="White">
    <StackPanel.Resources>
        <Storyboard x:Name="myStoryboard">
            <DoubleAnimation From="30" To="200" Duration="00:00:3" 
                Storyboard.TargetName="myRectangle" 
                Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
                <DoubleAnimation.EasingFunction>
                    <BounceEase Bounces="2" EasingMode="EaseOut" 
                                Bounciness="2"/>
                </DoubleAnimation.EasingFunction>
            </DoubleAnimation>
        </Storyboard>
    </StackPanel.Resources>
    <Rectangle x:Name="myRectangle" Fill="Blue" Width="200" Height="30"/>
</StackPanel>

Quando uma função de atenuação é aplicada a uma animação de / para / por , ela está alterando as características de função em tempo de como o valor interpola entre os valores de e para ao longo da duração da animação.When an easing function is applied to a From/To/By animation, it's changing the function- over-time characteristics of how the value interpolates between the From and To values over the Duration of the animation. Sem uma função de easing, seria uma interpolação linear.Without an easing function, that would be a linear interpolation.

Animações de valor de objeto discretoDiscrete object value animations

Um tipo de animação merece uma menção especial por ser a única maneira de aplicar um valor animado a propriedades que não são do tipo Double, Point ou Color.One type of animation deserves special mention because it's the only way you can apply an animated value to properties that aren't of type Double, Point, or Color. Este é o ObjectAnimationUsingKeyFrames da animação de quadro chave.This is the key-frame animation ObjectAnimationUsingKeyFrames. Animar usando valores Object é diferente porque não há a possibilidade de interpolar os valores entre os quadros.Animating using Object values is different because there's no possibility of interpolating the values between the frames. Quando o KeyTime do quadro é atingido, o valor animado é imediatamente definido como o valor especificado no Value do quadro chave.When the frame's KeyTime is reached, the animated value is immediately set to the value specified in the key frame's Value. Como não há interpolação, há somente um quadro chave que você usa na coleção de quadros chave ObjectAnimationUsingKeyFrames: DiscreteObjectKeyFrame.Because there's no interpolation, there's only one key frame you use in the ObjectAnimationUsingKeyFrames key frames collection: DiscreteObjectKeyFrame.

O Value de um DiscreteObjectKeyFrame geralmente é definido com o uso da sintaxe de elemento de propriedade porque o valor do objeto que você está tentando definir geralmente não pode ser expressado como uma cadeia de caracteres para preencher Value na sintaxe de atributo.The Value of a DiscreteObjectKeyFrame is often set using property element syntax, because the object value you are trying to set often is not expressible as a string to fill Value in attribute syntax. Você ainda pode usar a sintaxe de atributo se usar uma referência como StaticResource.You can still use attribute syntax if you use a reference such as StaticResource.

Um caso em que você verá um ObjectAnimationUsingKeyFrames usado nos modelos padrão é quando uma propriedade de modelo referencia um recurso Brush.One place you'll see an ObjectAnimationUsingKeyFrames used in the default templates is when a template property references a Brush resource. Esses recursos são objetos SolidColorBrush, não apenas um valor Color, e usam recursos que são definidos como temas do sistema (ThemeDictionaries).These resources are SolidColorBrush objects, not just a Color value, and they use resources that are defined as system themes (ThemeDictionaries). Eles podem ser atribuídos diretamente a um valor do tipo Brush, como TextBlock.Foreground e não precisam usar o direcionamento indireto.They can be assigned directly to a Brush-type value such as TextBlock.Foreground and don't need to use indirect targeting. No entanto, como um SolidColorBrush não é Double, Point ou Color, você precisa usar um ObjectAnimationUsingKeyFrames para usar o recurso.But because a SolidColorBrush is not Double, Point, or Color, you have to use a ObjectAnimationUsingKeyFrames to use the resource.

<Style x:Key="TextButtonStyle" TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid Background="Transparent">
                    <TextBlock x:Name="Text"
                        Text="{TemplateBinding Content}"/>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="PointerOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPointerOverForegroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Text" Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationPressedForegroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
...
                       </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Você também pode usar ObjectAnimationUsingKeyFrames para animar propriedades que usam um valor de enumeração.You also might use ObjectAnimationUsingKeyFrames to animate properties that use an enumeration value. Este é outro exemplo de um estado denominado que se origina dos modelos padrão do Windows Runtime.Here's another example from a named style that comes from the Windows Runtime default templates. Observe como ele define a propriedade Visibility que recebe uma constante de enumeração Visibility.Note how it sets the Visibility property that takes a Visibility enumeration constant. Nesse caso, você pode definir o valor usando a sintaxe de atributo.In this case you can set the value using attribute syntax. Você só precisa do nome da constante não qualificado de uma enumeração para definir uma propriedade com um valor de enumeração, por exemplo "Collapsed".You only need the unqualified constant name from an enumeration for setting a property with an enumeration value, for example "Collapsed".

<Style x:Key="BackButtonStyle" TargetType="Button">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="Button">
          <Grid x:Name="RootGrid">
            <VisualStateManager.VisualStateGroups>
              <VisualStateGroup x:Name="CommonStates">
              <VisualState x:Name="Normal"/>
...           <VisualState x:Name="Disabled">
                <Storyboard>
                  <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame Value="Collapsed" KeyTime="0"/>
                  </ObjectAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
            </VisualStateGroup>
...
          </VisualStateManager.VisualStateGroups>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Você pode usar mais de um DiscreteObjectKeyFrame para um conjunto de quadros ObjectAnimationUsingKeyFrames.You can use more than one DiscreteObjectKeyFrame for an ObjectAnimationUsingKeyFrames frame set. Essa pode ser uma maneira interessante de criar uma animação de "apresentação de slides" animando o valor de Image.Source, como um cenário de exemplo em que vários valores de objeto podem ser úteis.This might be an interesting way to create a "slide show" animation by animating the value of Image.Source, as an example scenario for where multiple object values might be useful.