属性动画技术概述

本主题介绍用于对属性进行动画处理的不同方法:故事板、局部动画、时钟和逐帧动画。

先决条件

若要了解本主题,应熟悉 动画概述中所述的基本动画功能。

动画处理的不同方法

由于用于动画处理属性的场景有很多不同,WPF 提供了几种方法来对属性进行动画处理。

对于每个方法,下表指示是否可以在样式、控件模板或数据模板中使用每个实例;是否可以在 XAML 中使用;以及该方法是否允许你以交互方式控制动画。 “Per-Instance”是指将动画或故事板直接应用于对象实例的技术,而不是在样式、控件模板或数据模板中应用。

动画技术 场景 支持 XAML 交互式可控制
情节提要动画 每个实例、StyleControlTemplateDataTemplate 是的 是的
本地动画 每个实例
时钟动画 每个实例 是的
每帧动画 每个实例 N/A

故事板动画

如果要在 XAML 中定义和应用动画、在动画启动后以交互方式控制动画、创建复杂动画树或在 StyleControlTemplateDataTemplate中创建动画,请使用 Storyboard。 要使对象由 Storyboard进行动画处理,它必须是 FrameworkElementFrameworkContentElement,或者必须用于设置 FrameworkElementFrameworkContentElement。 有关详细信息,请参阅 故事板概述

Storyboard 是一种特殊类型的容器 Timeline,它为包含的动画提供目标信息。 若要使用 Storyboard进行动画处理,请完成以下三个步骤。

  1. 声明 Storyboard 和一个或多个动画。

  2. 使用 TargetNameTargetProperty 附加属性来指定每个动画的目标对象和属性。

  3. (仅限代码)为 FrameworkElementFrameworkContentElement定义一个 NameScope。 注册已动画处理对象的名称,使用 FrameworkElementFrameworkContentElement

  4. 开始 Storyboard

开始 Storyboard 对其动画的属性应用并启动这些动画。 有两种方法可以开始 Storyboard:可以使用 Storyboard 类提供的 Begin 方法,也可以使用 BeginStoryboard 操作。 在 XAML 中进行动画处理的唯一方法是使用 BeginStoryboard 操作。 BeginStoryboard 操作可以在 EventTrigger、属性 TriggerDataTrigger中使用。

下表显示了支持每个 Storyboard 开始技术的不同位置:每个实例、样式、控件模板和数据模板。

故事板已开始使用… 每个实例 风格 控件模板 数据模板
BeginStoryboardEventTrigger 是的 是的 是的 是的 使用情节提要 对属性进行动画处理
BeginStoryboard 和属性 Trigger 是的 是的 是的 当属性值更改 时,触发动画
BeginStoryboardDataTrigger 是的 是的 是的 如何:在数据更改时触发动画
Begin 方法 是的 使用动画板为属性设置动画

有关 Storyboard 对象的详细信息,请参阅 故事板概述

本地动画

本地动画提供了一种方便的方法,用于对任何 Animatable 对象的依赖属性进行动画处理。 如果要将单个动画应用于属性,并且无需在动画启动时以交互方式控制动画,请使用本地动画。 与 Storyboard 动画不同,本地动画可以对与 FrameworkElementFrameworkContentElement不关联的对象进行动画处理。 你也不必为这种类型的动画定义 NameScope

本地动画只能在代码中使用,不能在样式、控件模板或数据模板中定义。 启动本地动画后无法以交互方式控制。

若要使用本地动画制作动画,请完成以下步骤。

  1. 创建 AnimationTimeline 对象。

  2. 使用要进行动画处理的对象 BeginAnimation 方法,将 AnimationTimeline 应用于指定的属性。

下面的示例演示如何对 Button的宽度和背景色进行动画处理。

/*

   This sample demonstrates how to apply non-storyboard animations to a property.
   To animate in markup, you must use storyboards.

*/

using namespace System;
using namespace System::Windows;
using namespace System::Windows::Navigation;
using namespace System::Windows::Media;
using namespace System::Windows::Media::Animation;
using namespace System::Windows::Shapes;
using namespace System::Windows::Controls;


namespace Microsoft {
   namespace Samples {
      namespace Animation {
         namespace LocalAnimations {
            // Create the demonstration.
            public ref class LocalAnimationExample : Page {

            public: 
               LocalAnimationExample ()
               {
                  WindowTitle = "Local Animation Example";
                  StackPanel^ myStackPanel = gcnew StackPanel();
                  myStackPanel->Margin = Thickness(20);

                  // Create and set the Button.
                  Button^ aButton = gcnew Button();
                  aButton->Content = "A Button";

                  // Animate the Button's Width.
                  DoubleAnimation^ myDoubleAnimation = gcnew DoubleAnimation();
                  myDoubleAnimation->From = 75;
                  myDoubleAnimation->To = 300;
                  myDoubleAnimation->Duration = Duration(TimeSpan::FromSeconds(5));
                  myDoubleAnimation->AutoReverse = true;
                  myDoubleAnimation->RepeatBehavior = RepeatBehavior::Forever;

                  // Apply the animation to the button's Width property.
                  aButton->BeginAnimation(Button::WidthProperty, myDoubleAnimation);

                  // Create and animate a Brush to set the button's Background.
                  SolidColorBrush^ myBrush = gcnew SolidColorBrush();
                  myBrush->Color = Colors::Blue;

                  ColorAnimation^ myColorAnimation = gcnew ColorAnimation();
                  myColorAnimation->From = Colors::Blue;
                  myColorAnimation->To = Colors::Red;
                  myColorAnimation->Duration = Duration(TimeSpan::FromMilliseconds(7000));
                  myColorAnimation->AutoReverse = true;
                  myColorAnimation->RepeatBehavior = RepeatBehavior::Forever;

                  // Apply the animation to the brush's Color property.
                  myBrush->BeginAnimation(SolidColorBrush::ColorProperty, myColorAnimation);
                  aButton->Background = myBrush;

                  // Add the Button to the panel.
                  myStackPanel->Children->Add(aButton);
                  this->Content = myStackPanel;
               };
            };
         }
      }
   }
}
/*

   This sample demonstrates how to apply non-storyboard animations to a property.
   To animate in markup, you must use storyboards.

*/

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

namespace Microsoft.Samples.Animation.LocalAnimations
{

    // Create the demonstration.
    public class LocalAnimationExample : Page
    {

        public LocalAnimationExample()
        {

            WindowTitle = "Local Animation Example";
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(20);

            // Create and set the Button.
            Button aButton = new Button();
            aButton.Content = "A Button";

            // Animate the Button's Width.
            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 75;
            myDoubleAnimation.To = 300;
            myDoubleAnimation.Duration =  new Duration(TimeSpan.FromSeconds(5));
            myDoubleAnimation.AutoReverse = true;
            myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;

            // Apply the animation to the button's Width property.
            aButton.BeginAnimation(Button.WidthProperty, myDoubleAnimation);

            // Create and animate a Brush to set the button's Background.
            SolidColorBrush myBrush = new SolidColorBrush();
            myBrush.Color = Colors.Blue;

            ColorAnimation myColorAnimation = new ColorAnimation();
            myColorAnimation.From = Colors.Blue;
            myColorAnimation.To = Colors.Red;
            myColorAnimation.Duration =  new Duration(TimeSpan.FromMilliseconds(7000));
            myColorAnimation.AutoReverse = true;
            myColorAnimation.RepeatBehavior = RepeatBehavior.Forever;

            // Apply the animation to the brush's Color property.
            myBrush.BeginAnimation(SolidColorBrush.ColorProperty, myColorAnimation);
            aButton.Background = myBrush;

            // Add the Button to the panel.
            myStackPanel.Children.Add(aButton);
            this.Content = myStackPanel;
        }
    }
}
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''This sample demonstrates how to apply non-storyboard animations to a property.
'''To animate in markup, you must use storyboards.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

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

Namespace Microsoft.Samples.Animation.LocalAnimations

    ' Create the demonstration.
    Public Class LocalAnimationExample
        Inherits Page

        Public Sub New()

            WindowTitle = "Animate Property Example"
            Dim myStackPanel As New StackPanel()
            myStackPanel.Margin = New Thickness(20)

            ' Create and set the Button.
            Dim aButton As New Button()
            aButton.Content = "A Button"

            ' Animate the Button's Width.
            Dim myDoubleAnimation As New DoubleAnimation()
            myDoubleAnimation.From = 75
            myDoubleAnimation.To = 300
            myDoubleAnimation.Duration = New Duration(TimeSpan.FromSeconds(5))
            myDoubleAnimation.AutoReverse = True
            myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever

            ' Apply the animation to the button's Width property.
            aButton.BeginAnimation(Button.WidthProperty, myDoubleAnimation)

            ' Create and animate a Brush to set the button's Background.
            Dim myBrush As New SolidColorBrush()
            myBrush.Color = Colors.Blue

            Dim myColorAnimation As New ColorAnimation()
            myColorAnimation.From = Colors.Blue
            myColorAnimation.To = Colors.Red
            myColorAnimation.Duration = New Duration(TimeSpan.FromMilliseconds(7000))
            myColorAnimation.AutoReverse = True
            myColorAnimation.RepeatBehavior = RepeatBehavior.Forever

            ' Apply the animation to the brush's Color property.
            myBrush.BeginAnimation(SolidColorBrush.ColorProperty, myColorAnimation)
            aButton.Background = myBrush

            ' Add the Button to the panel.
            myStackPanel.Children.Add(aButton)
            Me.Content = myStackPanel
        End Sub
    End Class
End Namespace

时钟动画

如果要在不使用 Storyboard 的情况下进行动画处理,并且希望在 Storyboard 启动后创建复杂的计时树或以交互方式控制动画,请使用 Clock 对象。 可以使用 Clock 对象对任何 Animatable 对象的依赖属性进行动画处理。

不能直接使用 Clock 对象对样式、控件模板或数据模板进行动画处理。 (动画和计时系统实际上使用 Clock 对象在样式、控件模板和数据模板中进行动画处理,但它必须从 Storyboard为你创建这些 Clock 对象。有关 Storyboard 对象与 Clock 对象之间的关系的详细信息,请参阅 动画和计时系统概述。)

若要将单个 Clock 应用于属性,请完成以下步骤。

  1. 创建 AnimationTimeline 对象。

  2. 使用 AnimationTimelineCreateClock 方法创建 AnimationClock

  3. 使用要进行动画处理的对象 ApplyAnimationClock 方法,将 AnimationClock 应用于指定的属性。

以下示例演示如何创建 AnimationClock 并将其应用于两个类似的属性。

/*
    This example shows how to create and apply
    an AnimationClock.
*/

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

namespace Microsoft.Samples.Animation.TimingBehaviors
{
    public class AnimationClockExample : Page
    {

        ScaleTransform myScaleTransform;

        public AnimationClockExample()
        {

            this.WindowTitle = "Opacity Animation Example";
            this.Background = Brushes.White;
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(20);

            // Create a button that with a ScaleTransform.
            // The ScaleTransform will animate when the
            // button is clicked.
            Button myButton = new Button();
            myButton.Margin = new Thickness(50);
            myButton.HorizontalAlignment = HorizontalAlignment.Left;
            myButton.Content = "Click Me";
            myScaleTransform = new ScaleTransform(1,1);
            myButton.RenderTransform = myScaleTransform;

            // Associate an event handler with the
            // button's Click event.
            myButton.Click += new RoutedEventHandler(myButton_Clicked);

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

        // Create and apply and animation when the button is clicked.
        private void myButton_Clicked(object sender, RoutedEventArgs e)
        {

            // Create a DoubleAnimation to animate the
            // ScaleTransform.
            DoubleAnimation myAnimation =
                new DoubleAnimation(
                    1, // "From" value
                    5, // "To" value
                    new Duration(TimeSpan.FromSeconds(5))
                );
            myAnimation.AutoReverse = true;

            // Create a clock the for the animation.
            AnimationClock myClock = myAnimation.CreateClock();

            // Associate the clock the ScaleX and
            // ScaleY properties of the button's
            // ScaleTransform.
            myScaleTransform.ApplyAnimationClock(
                ScaleTransform.ScaleXProperty, myClock);
            myScaleTransform.ApplyAnimationClock(
                ScaleTransform.ScaleYProperty, myClock);
        }
    }
}
'
'    This example shows how to create and apply
'    an AnimationClock.
'


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


Namespace Microsoft.Samples.Animation.TimingBehaviors
    Public Class AnimationClockExample
        Inherits Page

        Private ReadOnly myScaleTransform As ScaleTransform

        Public Sub New()

            WindowTitle = "Opacity Animation Example"
            Background = Brushes.White
            Dim myStackPanel As New StackPanel With {
                .Margin = New Thickness(20)
            }

                ' Create a button that with a ScaleTransform.
                ' The ScaleTransform will animate when the
                ' button is clicked.
            Dim myButton As New Button With {
                .Margin = New Thickness(50),
                .HorizontalAlignment = HorizontalAlignment.Left,
                .Content = "Click Me"
            }
            myScaleTransform = New ScaleTransform(1,1)
            myButton.RenderTransform = myScaleTransform


            ' Associate an event handler with the
            ' button's Click event.
            AddHandler myButton.Click, AddressOf myButton_Clicked

            myStackPanel.Children.Add(myButton)
            Content = myStackPanel
        End Sub

        ' Create and apply and animation when the button is clicked.
        Private Sub myButton_Clicked(sender As Object, e As RoutedEventArgs)

            ' Create a DoubleAnimation to animate the
            ' ScaleTransform.
            Dim myAnimation As New DoubleAnimation(1, 5, New Duration(TimeSpan.FromSeconds(5))) With {
                .AutoReverse = True
            } ' "To" value -  "From" value

            ' Create a clock the for the animation.
            Dim myClock As AnimationClock = myAnimation.CreateClock()

            ' Associate the clock the ScaleX and
            ' ScaleY properties of the button's
            ' ScaleTransform.
            myScaleTransform.ApplyAnimationClock(ScaleTransform.ScaleXProperty, myClock)
            myScaleTransform.ApplyAnimationClock(ScaleTransform.ScaleYProperty, myClock)
        End Sub
    End Class
End Namespace

若要创建计时树并使用它对属性进行动画处理,请完成以下步骤。

  1. 使用 ParallelTimelineAnimationTimeline 对象创建计时树。

  2. 使用根 ParallelTimelineCreateClock 创建 ClockGroup

  3. 遍历 ClockGroupChildren,并应用其子 Clock 对象。 对于每个 AnimationClock 子级,请使用要进行动画处理的对象 ApplyAnimationClock 方法,将 AnimationClock 应用于指定的属性

有关时钟对象的详细信息,请参阅 动画和计时系统概述

Per-Frame 动画:绕过动画和计时系统

如果需要完全绕过 WPF 动画系统,请使用此方法。 此方法的一种方案是物理动画,其中动画中的每个步骤都需要基于最后一组对象交互重新计算对象。

不能在样式、控件模板或数据模板内定义每帧动画。

要实现逐帧动画,请为包含要动画化对象的对象注册其 Rendering 事件。 每个帧调用一次此事件处理程序方法。 每当 WPF 将可视化树中的持久化呈现数据封送到合成树时,系统都会调用您的事件处理程序方法。

在事件处理程序中,执行动画效果所需的任何计算,并设置要使用这些值进行动画处理的对象的属性。

若要获取当前帧的呈现时间,可以将与此事件关联的 EventArgs 强制转换为 RenderingEventArgs,该 RenderingTime 属性可用于获取当前帧的呈现时间。

有关详细信息,请参阅 Rendering 页。

另请参阅