属性动画技术概述

本主题介绍了处理动画属性的不同方法:情节提要、本地动画、时钟和基于帧的动画。

先决条件

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

动画处理的不同方法

由于动画处理属性存在多种不同的方案,因此,WPF 为动画处理属性提供了几种方法。

对于每种方法,下表指明了它是否可以基于实例在样式、控件模板或数据模板中使用;它是否可以在 XAML 中使用;以及该方法是否使你能够以交互方式控制动画。 “基于实例”是指直接将动画或情节提要应用于对象实例(而不是在样式、控件模板或数据模板中应用)的技术。

动画技术 方案 支持 XAML 可以交互方式控制
情节提要动画 基于实例、StyleControlTemplateDataTemplate
本地动画 基于实例
时钟动画 基于实例
基于帧的动画 基于实例 空值

情节提要动画

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

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

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

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

  3. (仅限代码)为 FrameworkElementFrameworkContentElement 定义 NameScope。 使用该 FrameworkElementFrameworkContentElement.注册要进行动画处理的对象的名称。

  4. 开始 Storyboard

开始 Storyboard 会将动画应用到它们进行动画处理的属性并启动它们。 有两种开始 Storyboard 的方法:可以使用 Storyboard 类提供的 Begin 方法,或者使用 BeginStoryboard 操作。 使用 BeginStoryboard 操作是在 XAML 中进行动画处理的唯一方法。 可以在 EventTriggerTrigger 属性或 DataTrigger 中使用 BeginStoryboard 操作。

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

情节提要开始时使用… 基于实例 样式 控件模板 数据模板 示例
BeginStoryboardEventTrigger 使用情节提要对属性进行动画处理
BeginStoryboardTrigger 属性 在属性值更改时触发动画
BeginStoryboardDataTrigger 如何:在数据更改时触发动画
Begin 方法 No No 使用情节提要对属性进行动画处理

有关 Storyboard 对象的详细信息,请参阅 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 的情况下进行动画处理,并且想在动画启动后创建复杂的计时树或以交互方式控制动画,请使用 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. 使用 ParallelTimeline 根的 CreateClock 以创建 ClockGroup

  3. 循环访问 ClockGroupChildren 并应用其子 Clock 对象。 对于每个 AnimationClock 子项,请使用想要进行动画处理的对象的 ApplyAnimationClock 方法以将 AnimationClock 应用到所指定的属性

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

基于帧的动画:绕过动画和计时系统

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

基于帧的动画无法在样式、控件模板或数据模板内定义。

若要逐帧进行动画处理,应注册对象的 Rendering 事件,该对象包含想要进行动画处理的对象。 每帧会调用一次此事件处理程序方法。 每次 WPF 将可视化树中的持久呈现数据封送到复合树时,都将调用事件处理程序方法。

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

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

有关更多信息,请参阅 Rendering 页。

另请参阅