|
|
|
|
|
Animations in Windows Presentation Foundation
by Keyvan Nayyeri |
Summary
In the fourth article of our series about UniveRSS we discuss animations
in XAML and Windows Presentation Foundation because animations are a main part of the UniveRSS
user interface and an important part of WPF as well as being one of its powerful features.
In this article we walk through the principles of animations in WPF and talk about StoryBoard,
RepeatBehavior, Transformation, ParallelTimeLine and KeyFrame.
|
|
Introduction
Animations are one of most important aspects of Windows Presentation Foundation and they make a
powerful part of this new technology in .NET Framework 3.0. Creating an animation in preceding graphic
engines was a time-consuming process but in WPF things are simpler and you can build animations easily.
Animations are a built-in part of XAML as markup language for declaring user interfaces in WPF and several
options are available to build animations.
UniveRSS as a 3D RSS reader specifically designed for .NET 3.0 with WPF comes with animations at the heart of
its user interface. Feeds are presented in constantly rotating cubes suspended in a virtual universe. These 3D
animations are a main part of the UniveRSS application so we decided to dedicate an article to animations in
Windows Presentation Foundation to show the principles of animations in these new technologies.
In this article we want to talk about animations in XAML and WPF. First we begin with a background then will
talk about StoryBoards, different animation types, RepeatBehavior, Transformations, ParallelTimeLine and KeyFrames.
|
|
Background
Timing is crucial in building animations. Timing is the process to calculate times for each frame in an animation,
when it starts, when it ends and total time of an animation. In older graphic engines timing was a little hard
to accomplish but in WPF massively simplified, with the WPF engine doing the job for you.
Usually an animation consists of changing a color or an angle or width and height of a control or transforming
a shape or control. WPF supports all these animation types out of the box. You can create your animations based on
different events on a WPF UI. You build your animations using RoutedEvents and triggers. You should use StoryBoard
elements to declare your animations. Each StoryBoard may contain one or more basic animation types. Later in this
article you’ll read about StoryBoards and other elements that play a role in animations.
|
|
StoryBoards
StoryBoard is the core element of animations. StoryBoards must be nested inside a BeginStoryBoard element
inside event triggers. Each StoryBoard consists of one or more basic animation types to animate a control.
This element comes with two important properties: StoryBoard.TargetName and StoryBoard.TargetProperty.
Storyboard specifies the name of the element that should be animated and TargetName specifies the property
of the element that should be animated by StoryBoard. StoryBoard.TargetProperty must be set to the correct
property based on the hierarchy of elements, sub-elements and attributes in XAML.
Inside the StoryBoard you can put one or more basic animation types based on the animation that you want to
build. Generally all basic animation types share the following important properties:
- From: Initial value of property when animation begins.
- To: Last value of property when animation ends.
- By: Intermediate value of property at the middle of animation. It’s a bridge between From and To. This property is optional.
- Duration: Total time of animation.
- RepeatBehavior: Behavior of animation. You’ll read about this property later.
Listing 1 is an example of StoryBoards in action. In the script the background color of a Button is animated from Pink
to Blue and then to Green in 6 seconds whenever the user moves the mouse over the button.
|
|
Listing 1
<Window x:Class="UniveRSS.Animations.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Animations in WPF" Height="300" Width="300">
<Grid>
<Grid.Triggers>
<EventTriggerRoutedEvent="Rectangle.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="myButton"
Storyboard.TargetProperty="(Background).
(SolidColorBrush.Color)">
<ColorAnimation From="Pink"
To="Green"
By="Blue"
Duration="0:0:6" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Grid.Triggers>
<Button Name="myButton"
Width="150"
Height="35"
Background="Pink">
Click Me!
</Button>
</Grid>
</Window>
For ease of demonstration, the animation image in Figure 1
is shown to run unlimited iterations.
Figure 1
|
|
Repeat Behaviour
Using two properties you can change the behavior of your animations in two ways. You can reverse the
animation by setting the AutoReverse property of each animation type to true.
You may also set RepeatBehavior of each animation type in order to manage the number of iterations for
each animation. You can set this property to Forever to force your animation to run forever (until you stop
the application). You can also set it to different numbers of iterations to force it to iterate for the desired
number of times.
Listing 2 is the reverse animation of Listing 1 that runs for three times.
|
|
Listing 2
<Window x:Class="UniveRSS.Animations.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Animations in WPF" Height="300" Width="300">
<Grid>
<Grid.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="myButton"
Storyboard.TargetProperty="(Background).
(SolidColorBrush.Color)">
<ColorAnimation From="Pink"
To="Green"
By="Blue"
Duration="0:0:6"
RepeatBehavior="3x"
AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Grid.Triggers>
<Button Name="myButton"
Width="150"
Height="35"
Background="Pink">
Click Me!
</Button>
</Grid>
</Window>
Output is shown as a .gif file in Figure 2.
Figure 4
|
|
Transformations
Transformations are another way to animate controls. Using transformations you can change
the angle of each control which is a common way to animate objects in user interfaces. To make transformations
possible, you have to use one DoubleAnimation to change the RenderTransform of an object when an event occurs.
For example in Listing 3 I used transformations to change the angle of RotateTransform to transform a button from
0 to 180 degrees in 6 seconds.
|
|
Listing 3
<Window x:Class="UniveRSS.Animations.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Animations in WPF" Height="300" Width="300">
<Grid>
<Grid.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="myButton"
Storyboard.TargetProperty="(RenderTransform).
(RotateTransform.Angle)">
<DoubleAnimation From="0"
To="180"
By="90"
Duration="0:0:6"
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Grid.Triggers>
<Button Name="myButton"
Width="150"
Height="35"
Background="Pink">
Click Me!
</Button>
</Grid>
</Window>
You can see the output in Figure 3
Figure 3
|
|
ParallelTimeLine
Sometimes you need to create two or more animations that run in parallel. This is very easy
to accomplish in Windows Presentation Foundation. All you need to do is nest your StoryBoards inside a ParallelTimeLine
element within a parent StoryBoard. This way, all those StoryBoards and their animations will run in parallel.
Listing 4 is an example of ParallelTimeLine where I animate a button to change its background color while its
RenderTransform angle is changing from 0 to 180 degrees (In actual fact, I merged two animations that are provided in
Listing 1 and Listing 3).
|
|
Listing 4
<Window x:Class="UniveRSS.Animations.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Animations in WPF" Height="300" Width="300">
<Grid>
<Grid.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ParallelTimeline>
<Storyboard Storyboard.TargetName="myButton"
Storyboard.TargetProperty="(Background).
(SolidColorBrush.Color)">
<ColorAnimation From="Pink"
To="Green"
By="Blue"
Duration="0:0:6" />
</Storyboard>
<Storyboard Storyboard.TargetName="myButton"
Storyboard.TargetProperty="(RenderTransform).
(RotateTransform.Angle)">
<DoubleAnimationFrom="0"
To="180"
By="90"
Duration="0:0:6" />
</Storyboard>
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Grid.Triggers>
<Button Name="myButton"
Width="150"
Height="35"
Background="Pink">
<Button.RenderTransform>
<RotateTransform Angle="0"CenterX="105"CenterY="30" />
</Button.RenderTransform>
Click Me!
</Button>
</Grid>
</Window>
Output is shows in Figure 4 as unlimited iterations.
Figure 4
|
|
KeyFrame
By default all built-in animation types use a symmetric way to animate
elements and divide total time into equal frames but sometimes you need to manage the length of time that
each frame of animation appears in output. In this case you can declare different values for different frames
by using different types of KeyFrames. Each basic animation type has a corresponding KeyFrame to let you
declare KeyFrames for that type. For example in Listing 5 I use LinearDoubleKeyFrames to change the Width of a
button from 60 to 120 with different values on each time frame.
|
|
Listing 5
<Window x:Class="UniveRSS.Animations.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Animations in WPF" Height="300" Width="300">
<Grid>
<Grid.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="myButton"
Storyboard.TargetProperty="Width">
<DoubleAnimationUsingKeyFrames Duration="0:0:8">
<LinearDoubleKeyFrame KeyTime="0:0:2" Value="60"/>
<LinearDoubleKeyFrame KeyTime="0:0:4" Value="80"/>
<LinearDoubleKeyFrame KeyTime="0:0:6" Value="100"/>
<LinearDoubleKeyFrame KeyTime="0:0:8" Value="120"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Grid.Triggers>
<Button Name="myButton"
Width="60"
Height="35"
Background="Pink">
Click Me!
</Button>
</Grid>
</Window>
Figure 5 shows the result as unlimited iterations.
Figure 5
|
|
How it is done in UniveRSS
3D effects and animations differ in WPF and are slightly more complicated than 2D effects.
3D animations need some calculations in order to have the right values for animation elements and attributes.
In our showcase, UniveRSS, all animations are done frame by frame explicitly using built-in 3D animation features
from the Windows Presentation Foundation. In later articles 3D animations will be described in greater detail.
|
Keyvan Nayyeri has been a geek and programmer since he was 10. He has a BS degree in Applied Mathematics and as an experienced software architect and developer he is also a MVP from Telligent for Community Server technology.
Keyvan is a co-author for Wrox press and also an author for ASP Alliance, DotNetSlackers and Code Project .NET communities. Currently he’s contributed in some projects such as BlogML, CSModules and Windows Live Writer Plugins. He edits his blog on .NET, Community Server and Technology.
|