Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Advanced Animations in WPF

0.00/5 (No votes)
13 Apr 2013 1  
This article describes advanced animations in WPF.

Introduction

This article is a continuation of my previous article Animation using Storyboards in WPF. In that article, I had written about Double Animation and Color Animation. In this article, I am describing KeyFrame Animation, Path Animation, and Matrix Animation. Double Animation and Color Animation are simple animations which have a starting point and ending point. As such, it is difficult to use them for more complex animations. We can use KeyFrame Animation, Path Animation, and Matrix Animation to have more control over complex animations.

  1. Keyframe animations are based on keyframes which define the important points of an animation. In-between frames are drawn later. WPF automatically generates the in-between frames.
  2. Path animations allow you to define the path which an object follows, using PathGeometry. This is a more easier approach than keyframe animation.
  3. Matrix animation is a special type of path animation. Matrix animation can be used to control the position and orientation of an object.

Background

Linear KeyFrame Animation

The following code animates an ellipse using a linear keyframe animation:

<Canvas>
    <Ellipse Fill="Red" Width="70" Height="70">
        <Ellipse.Triggers>
            <EventTrigger RoutedEvent="Ellipse.Loaded">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation From="0" To="400" Duration="0:0:5" 
                                 Storyboard.TargetProperty="(Canvas.Left)" 
                                 RepeatBehavior="Forever" AutoReverse="True"/>
                            <DoubleAnimationUsingKeyFrames Duration="0:0:2" 
                                   Storyboard.TargetProperty="(Canvas.Top)" 
                                   RepeatBehavior="Forever">
                                <DoubleAnimationUsingKeyFrames.KeyFrames>
                                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
                                    <LinearDoubleKeyFrame Value="50" KeyTime="0:0:0.5"/>
                                    <LinearDoubleKeyFrame Value="200" KeyTime="0:0:1"/>
                                    <LinearDoubleKeyFrame Value="50" KeyTime="0:0:1.5"/>
                                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:2"/>
                                </DoubleAnimationUsingKeyFrames.KeyFrames>
                            </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Ellipse.Triggers>
    </Ellipse>
</Canvas>
Colourised in 31ms

In the above code, a simple DoubleAnimation is used to control the horizontal movement of the ellipse from 0 to 400 in a duration of 5 seconds. The DoubleAnimationUsingKeyFrames element controls the vertical movement of the ellipse. It specifies 5 keyframes at intervals of 0.5 seconds. The LinearDoubleKeyFrame element is used to specify the keyframes. LinearDoubleKeyFrame does not produce a smooth animation because the change in value between two frames is constant.

Following is the output of the above code:

Spline KeyFrame Animation

To create a smooth animation, we can use SplineDoubleKeyFrame. SplineDoubleKeyFrame uses a mathematical function to calculate how the object should accelerate or decelerate. The KeySpline attribute can be used to specify this value.

The following figures illustrate this:

The following code uses SplineDoubleKeyFrame to produce smooth animation:

<Canvas>
    <Ellipse Fill="Red" Width="70" Height="70">
        <Ellipse.Triggers>
            <EventTrigger RoutedEvent="Ellipse.Loaded">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation From="0" To="400" Duration="0:0:10" 
                             Storyboard.TargetProperty="(Canvas.Left)" 
                             RepeatBehavior="Forever" AutoReverse="True"/>
                        <DoubleAnimationUsingKeyFrames Duration="0:0:2" 
                               Storyboard.TargetProperty="(Canvas.Top)" 
                               RepeatBehavior="Forever">
                            <DoubleAnimationUsingKeyFrames.KeyFrames>
                                <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
                                        <SplineDoubleKeyFrame Value="50" 
                                           KeyTime="0:0:0.5" KeySpline="0.4,0 0.7,0.7"/>
                                        <SplineDoubleKeyFrame Value="200" 
                                           KeyTime="0:0:1" KeySpline="0.2,0.2 0.7,0.4"/>
                                        <SplineDoubleKeyFrame Value="50" 
                                           KeyTime="0:0:1.5" KeySpline="0,0.3 0.75,0.75"/>
                                        <SplineDoubleKeyFrame Value="0" 
                                           KeyTime="0:0:2.0" KeySpline="0.25,0.25 0.6,1"/>
                                    </DoubleAnimationUsingKeyFrames.KeyFrames>
                            </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Ellipse.Triggers>
    </Ellipse>
</Canvas>
Colourised in 37ms

The above code produces a more realistic animation by causing the animation to accelerate gradually after starting slowly.

The following is the output of the above code:

Path Animation

Path animation can be used to move an object on a canvas by changing its position. This can be done by setting the Canvas.Left and Canvas.Top properties. Since these properties are of type double, we can use DoubleAnimationUsingPath to animate the object.

Following is the code which uses a path animation to move an ellipse on an elliptical path.

<Canvas>
    <Canvas.Resources>
        <PathGeometry x:Key="MyGeometry" 
          Figures="M 0,30 A 30,30 180 0 1 60,30 30,30 180 0 1 0,30"/>
    </Canvas.Resources>
    <Ellipse Width="50" Height="50" Fill="Green">
        <Ellipse.Triggers>
            <EventTrigger RoutedEvent="Window.Loaded">
                <BeginStoryboard>
                    <Storyboard RepeatBehavior="Forever">
                        <DoubleAnimationUsingPath Source="X" 
                          Storyboard.TargetProperty="(Canvas.Left)" 
                          PathGeometry="{StaticResource MyGeometry}"/>
                        <DoubleAnimationUsingPath Source="Y" 
                          Storyboard.TargetProperty="(Canvas.Top)" 
                          PathGeometry="{StaticResource MyGeometry}"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Ellipse.Triggers>
    </Ellipse>
</Canvas>
Colourised in 10ms

The above code creates a PathGeometry object as a canvas resource. Then it uses the PathGeometry attribute of DoubleAnimationUsingPath to change the position of the ellipse on the path. To understand the syntax of PathGeometry, refer to the following link: http://msdn.microsoft.com/en-us/library/ms752293.aspx.

Following is the output of the above code:

Matrix Animation

Matrix animation can be used to control an object's position and orientation. We can control the rotation of the object on a path using the DoesRotateWithTangent property. I have used the following code to move an arrow on a path.

<Canvas>
    <Path Name="MyPath" StrokeThickness="7">
        <Path.Stroke>
            <SolidColorBrush x:Name="MyBrush" Color="Red"/>
        </Path.Stroke>
        <Path.Data>
            <PathGeometry Figures="M 0,0 H45 M 35,-10 L 45,0,35,10"/>
        </Path.Data>
        <Path.RenderTransform>
            <MatrixTransform x:Name="MyMatrixTransform">
                <MatrixTransform.Matrix>
                    <Matrix/>
                </MatrixTransform.Matrix>
            </MatrixTransform>
        </Path.RenderTransform>
        <Path.Triggers>
            <EventTrigger RoutedEvent="Window.Loaded">
                <BeginStoryboard>
                    <Storyboard>
                        <Storyboard AutoReverse="True" RepeatBehavior="Forever">
                            <ColorAnimation Storyboard.TargetName="MyBrush" 
                               Storyboard.TargetProperty="Color" From="Red" To="Green" 
                               BeginTime="0:0:0" Duration="0:0:1"/>
                            <ColorAnimation Storyboard.TargetName="MyBrush" 
                               Storyboard.TargetProperty="Color" From="Green" 
                               To="Blue" BeginTime="0:0:1" Duration="0:0:1"/>
                            <ColorAnimation Storyboard.TargetName="MyBrush" 
                               Storyboard.TargetProperty="Color" From="Blue" 
                               To="Cyan" BeginTime="0:0:2" Duration="0:0:1"/>
                            <ColorAnimation Storyboard.TargetName="MyBrush" 
                               Storyboard.TargetProperty="Color" From="Cyan" 
                               To="Magenta" BeginTime="0:0:3" Duration="0:0:1"/>
                            <ColorAnimation Storyboard.TargetName="MyBrush" 
                               Storyboard.TargetProperty="Color" From="Magenta" 
                               To="Red" BeginTime="0:0:4" Duration="0:0:1"/>
                        </Storyboard>
                        <MatrixAnimationUsingPath Storyboard.TargetName="MyMatrixTransform" 
                                  Storyboard.TargetProperty="Matrix" DoesRotateWithTangent="True" 
                                  Duration="0:0:5" RepeatBehavior="Forever">
                            <MatrixAnimationUsingPath.PathGeometry>
                                <PathGeometry Figures="M 100,200 C 100,25 400,350 400,175"/>
                            </MatrixAnimationUsingPath.PathGeometry>
                        </MatrixAnimationUsingPath>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Path.Triggers>
    </Path>
</Canvas>
Colourised in 53ms

The above code uses a MatrixAnimationUsingPath to move an arrow along a path defined using a PathGeometry and ColorAnimation to change the color of the arrow as it moves. I have created an arrow as follows using the following path geometry:

<PathGeometry Figures="M 0,0 H45 M 35,-10 L 45,0,35,10"/>
Colourised in 1ms

and a path as follows:

using the following path geometry:

<PathGeometry Figures="M 100,200 C 100,25 400,350 400,175"/>
Colourised in 0ms

The DoesRotateWithTangent property is set to true to rotate the arrow along the path.

The following is the output of the above code:

The following is the output of the above code if the DoesRotateWithTangent property is set to false:

Using the code

I have created an application which demonstrates all the above animations using a tabbed interface.

Points of interest

I have used Visual C# 2010 Express Edition to do all the coding. I hope that readers find this article helpful in understanding the various aspects of animation in WPF.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here