Click here to Skip to main content
Click here to Skip to main content

Animation using Storyboards in WPF

By , 13 Apr 2013
 

Introduction

Animation in WPF has been made easier because WPF achieves animation by modifying properties of elements, whereas in Windows Forms, a developer has to create a timer and modify the appearance of elements on the tick event of a timer. WPF uses its own timing system which can be written using managed code and XAML. The internal work of redrawing the screen is handled efficiently by WPF. While animating using WPF, you just need to focus on the effects you want to create without bothering about how to achieve those effects.

To demonstrate this, I have created a Waving Flag animation which uses a series of images displayed in a sequence.

Background

DoubleAnimation

WPF achieves animation by animating element properties. For example, if you want to produce a zoom in or zoom out effect for a rectangle, you can animate the width and height properties. The following code animates a rectangle by modifying its width and height properties.

<Rectangle Name="myrect" Width="1" Height="1">
    <Rectangle.Fill>
        <SolidColorBrush Color="Red"/>
    </Rectangle.Fill>   
    <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard>
                <Storyboard RepeatBehavior="Forever">
                    <DoubleAnimation Storyboard.TargetName="myrect" 
                       Storyboard.TargetProperty="Width" From="1" To="350" 
                       Duration="0:0:1" BeginTime="0:0:0"/>
                    <DoubleAnimation Storyboard.TargetName="myrect" 
                       Storyboard.TargetProperty="Height" From="1" To="250" 
                       Duration="0:0:1" BeginTime="0:0:1"/>
                    <DoubleAnimation Storyboard.TargetName="myrect" 
                       Storyboard.TargetProperty="Height" From="250" 
                       To="1" Duration="0:0:1" BeginTime="0:0:2"/>
                    <DoubleAnimation Storyboard.TargetName="myrect" 
                       Storyboard.TargetProperty="Width" From="350" To="1" 
                       Duration="0:0:1" BeginTime="0:0:3"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Rectangle.Triggers>
</Rectangle>

This code triggers the animation automatically when the window is loaded. The code adds an EventTrigger to the rectangle. The BeginStoryboard action runs a storyboard. This storyboard uses four DoubleAnimations. The first DoubleAnimation increases the width of the rectangle from 1 to 350. The second one increases the height from 1 to 250. The third and fourth do the reverse by decreasing the height and width back to 1. The four DoubleAnimations are made to run in a sequence by setting the BeginTime attribute such that each animation starts when the previous is over. The RepeatBehavior attribute of the Storyboard is assigned the value "Forever" which makes the animation run indefinitely.

Following is the output of the above code:

Controlling the Animation from Code-Behind

The animation can be controlled from the code-behind by creating a storyboard as a window resource and locating it in code by using the TryFindResource method as follows:

Storyboard s = (Storyboard)TryFindResource("sb");

Following is the code to create the Storyboard resource:

<Window.Resources>
    <Storyboard x:Key="sb" RepeatBehavior="Forever">
        <DoubleAnimation Storyboard.TargetName="myrect" 
          Storyboard.TargetProperty="Width" From="1" To="350" 
          Duration="0:0:1" BeginTime="0:0:0"/>
        <DoubleAnimation Storyboard.TargetName="myrect" 
          Storyboard.TargetProperty="Height" From="1" To="250" 
          Duration="0:0:1" BeginTime="0:0:1"/>
        <DoubleAnimation Storyboard.TargetName="myrect" 
          Storyboard.TargetProperty="Height" From="250" To="1" 
          Duration="0:0:1" BeginTime="0:0:2"/>
        <DoubleAnimation Storyboard.TargetName="myrect" 
          Storyboard.TargetProperty="Width" From="350" To="1" 
          Duration="0:0:1" BeginTime="0:0:3"/>
    </Storyboard>
</Window.Resources>

The following is the code to control the animation programmatically:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void btnStart_Click(object sender, RoutedEventArgs e)
    {
        // Locate Storyboard resource
        Storyboard s = (Storyboard)TryFindResource("sb");
        s.Begin();	// Start animation
    }

    private void btnStop_Click(object sender, RoutedEventArgs e)
    {
        Storyboard s = (Storyboard)TryFindResource("sb");
        s.Stop();	// Stop animation
    }

    private void btnPause_Click(object sender, RoutedEventArgs e)
    {
        Storyboard s = (Storyboard)TryFindResource("sb");
        s.Pause();	// Pause animation
    }

    private void btnResume_Click(object sender, RoutedEventArgs e)
    {
        Storyboard s = (Storyboard)TryFindResource("sb");
        s.Resume();	// Resume animation
    }
}

Following is the output of the above code:

Fade In and Fade Out Animation Using DoubleAnimation

Fade In and Fade Out Animation effects can be created using the Opacity property as follows:

<Rectangle Name="myrect" Width="350" Height="250">
    <Rectangle.Fill>
        <SolidColorBrush x:Name="brush" Color="Red"/>
    </Rectangle.Fill>
    <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetName="myrect" 
                        Storyboard.TargetProperty="Opacity" From="0" To="1" 
                        Duration="0:0:1" BeginTime="0:0:0" AutoReverse="True" 
                        RepeatBehavior="Forever"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Rectangle.Triggers>
</Rectangle>

The above code changes the opacity of the rectangle from 0 (completely transparent) to 1 (completely opaque).

The output of the above code is as follows:

ColorAnimation

We can use ColorAnimation to animate the Color property of a rectangle. Following is the code to produce color animation:

<Rectangle Name="myrect" Width="350" Height="250">
    <Rectangle.Fill>
        <SolidColorBrush x:Name="brush" Color="Red"/>
    </Rectangle.Fill>
    <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard>
                <Storyboard RepeatBehavior="Forever">
                    <ColorAnimation Storyboard.TargetName="brush" 
                      Storyboard.TargetProperty="Color" From="Red" To="Green" 
                      Duration="0:0:1" BeginTime="0:0:0"/>
                    <ColorAnimation Storyboard.TargetName="brush" 
                      Storyboard.TargetProperty="Color" From="Green" To="Blue" 
                      Duration="0:0:1" BeginTime="0:0:1"/>
                    <ColorAnimation Storyboard.TargetName="brush" 
                      Storyboard.TargetProperty="Color" From="Blue" To="Yellow" 
                      Duration="0:0:1" BeginTime="0:0:2"/>
                    <ColorAnimation Storyboard.TargetName="brush" 
                      Storyboard.TargetProperty="Color" From="Yellow" 
                      To="Red" Duration="0:0:1" BeginTime="0:0:3"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Rectangle.Triggers>
</Rectangle>

This code uses four ColorAnimations to change the color of the rectangle. The timing of the color change is controlled by using the BeginTime property.

The above code produces the following output:

Animating Gradient Using ColorAnimation

ColorAnimation can also be used to create gradient animation. The following code can be used for this:

<Rectangle Name="myrect" Width="350" Height="250">
    <Rectangle.Fill>
        <LinearGradientBrush x:Name="brush" StartPoint="0,0" EndPoint="1,1">
            <GradientStop x:Name="stop1" Offset="0" Color="Red"/>
            <GradientStop x:Name="stop2" Offset="0.5" Color="Green"/>
            <GradientStop x:Name="stop3" Offset="1" Color="Blue"/>
        </LinearGradientBrush>
    </Rectangle.Fill>
    <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard>
                <Storyboard RepeatBehavior="Forever">
                    <ColorAnimation Storyboard.TargetName="stop1" Storyboard.TargetProperty="Color" 
                       From="Red" To="Green" Duration="0:0:1" BeginTime="0:0:0"/>
                    <ColorAnimation Storyboard.TargetName="stop1" Storyboard.TargetProperty="Color" 
                       From="Green" To="Blue" Duration="0:0:1" BeginTime="0:0:0.5"/>
                    <ColorAnimation Storyboard.TargetName="stop1" Storyboard.TargetProperty="Color" 
                       From="Blue" To="Red" Duration="0:0:1" BeginTime="0:0:1"/>
                    <ColorAnimation Storyboard.TargetName="stop2" Storyboard.TargetProperty="Color" 
                       From="Green" To="Blue" Duration="0:0:1" BeginTime="0:0:0"/>
                    <ColorAnimation Storyboard.TargetName="stop2" Storyboard.TargetProperty="Color" 
                       From="Blue" To="Red" Duration="0:0:1" BeginTime="0:0:0.5"/>
                    <ColorAnimation Storyboard.TargetName="stop2" Storyboard.TargetProperty="Color" 
                       From="Red" To="Green" Duration="0:0:1" BeginTime="0:0:1"/>
                    <ColorAnimation Storyboard.TargetName="stop3" Storyboard.TargetProperty="Color" 
                       From="Blue" To="Red" Duration="0:0:1" BeginTime="0:0:0"/>
                    <ColorAnimation Storyboard.TargetName="stop3" Storyboard.TargetProperty="Color" 
                       From="Red" To="Green" Duration="0:0:1" BeginTime="0:0:0.5"/>
                    <ColorAnimation Storyboard.TargetName="stop3" Storyboard.TargetProperty="Color" 
                       From="Green" To="Blue" Duration="0:0:1" BeginTime="0:0:1"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Rectangle.Triggers>
</Rectangle>

The above code initially creates a rectangle having a linear gradient of Red, Green, and Blue colors. Then it animates each gradient to change its color.

Following is the output of the above code:

Using the Code

I have created an application which displays an animated Indian flag. The full XAML code of the application is as follows:

<Window x:Class="AnimatedFlag.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Indian Flag" Height="350" Width="525">
    <Grid>
        <Image Name="flagImage" Margin="12">
            <Image.Triggers>
                <EventTrigger RoutedEvent="Window.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Name="da" Storyboard.TargetName="flagImage" 
                               Storyboard.TargetProperty="Width" From="200" To="200" 
                               Duration="0:0:0.1" Completed="DoubleAnimation_Completed"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Image.Triggers>
        </Image>
    </Grid>
</Window>

This code creates a dummy animation. I call it dummy animation because it does not actually change any property. The <DoubleAnimation> element just uses the Width property of the image but the values of the From and To attributes are the same (200). The Duration attribute specifies the animation duration as 0.1 second. It uses the Completed event handler to restart the animation after it is completed. The code-behind code is as follows:

public partial class MainWindow : Window
{
    int ctr = 1;
    public MainWindow()
    {
        InitializeComponent();
    }

    private void DoubleAnimation_Completed(object sender, EventArgs e)
    {
        ShowImage();	// Display Image
        da.BeginAnimation(Image.WidthProperty, da);	// Start Animation
    }

    private void ShowImage()
    {
        string filename = "Images/Flag" + ctr + ".jpg";
        BitmapImage image = new BitmapImage();
        image.BeginInit();
        image.UriSource = new Uri(filename, UriKind.Relative);
        image.EndInit();
        flagImage.Source = image;
        ctr++;
        if (ctr > 6)
        {
            ctr = 1;	// Display first image after the last image
        }
    }
}

In the above code, the DoubleAnimation_Completed event handler calls the ShowImage() function to display six images in a sequence. It uses the BeginAnimation() method of the DoubleAnimation class to restart the animation. The first parameter of the BeginAnimation method is Image.WidthProperty which is a DependencyProperty. The second parameter is the AnimationTimeline object.

The output of the program is as follows:

Points of Interest

I have created this application using Microsoft Visual C# 2010 Express Edition. I hope that this article will help in understanding the concepts of Storyboard and Animations in WPF.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Azim Zahir
Instructor / Trainer NIIT, India
India India
I am a trainer by profession. Currently I am working with NIIT (Mumbai, India) as a Senior Faculty. I enjoy programming as a hobby. My favorite technologies are Flash, Flex and Silverlight.
 
Of late I have developed keen interest in WPF and Windows Mobile programming.
 
Apart from computers, my favorite pastime is bicycling.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionApplying same wave effect to a static "wave" imagememberMember 293896111-Jun-13 13:03 
Hi,
 
A very good article, which helped me a lot.
I would like to apply the same kind of an animation to a wave image ... So the waves should move with animation..
Something like this http://depositphotos.com/24922197/stock-illustration-Fancy-green-wave.html[^]
 
I understand that I will have to create image frames to have that smooth wave effect.. Can you guide me on how to create those or any other way of WPF animation can be used here?
AnswerRe: Applying same wave effect to a static "wave" imagememberAzim Zahir11-Jun-13 23:16 
Hello,
 
If you have multiple image frames, then you can code similar to the demo application from this article. There is also a library called Pixel Shader Effects Library that can be used to create wave effects. It can be downloaded from here: http://wpffx.codeplex.com/[^]. It also supports various other effects.
 
Regards.
GeneralMy vote of 5professionalSS Reddy18-May-13 20:58 
Nice Post
QuestionGreat, clear, useful article :-)membercausg29-Apr-13 4:40 
You seem to be a great teacher. Thank you so much!
AnswerRe: Great, clear, useful article :-)memberAzim Zahir29-Apr-13 16:41 
Thank you very much... Smile | :)
GeneralMy vote of 5memberloulou_7501614-Mar-13 10:00 
Thank you for this short and clear explanation.
GeneralRe: My vote of 5memberAzim Zahir17-Mar-13 0:18 
Thanks a lot. Smile | :)
GeneralMy vote of 5memberSalCon7-Mar-13 4:05 
Very good for a beginner. Exactly what I was looking for.
GeneralRe: My vote of 5memberAzim Zahir11-Mar-13 19:12 
Thanks... I am glad that this has helped you... Smile | :)
GeneralMy vote of 5memberCzimerA17-Jan-13 0:23 
Very nice tutorial
GeneralRe: My vote of 5memberAzim Zahir18-Jan-13 15:37 
Thank you Smile | :)
QuestionWhat's wrong with following code?membermohammed190.sobhy4-Dec-12 17:33 
<Storyboard x:Key="lblAnimation1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.4" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.8" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:2.2" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:2.6" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:3.4" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:10" Value="1"/>
</DoubleAnimationUsingKeyFrames>
 
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
 
-----------------------------------------
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
data = (new PhoneBookServiceClient()).GetContact(1).ToList();
lstview.ItemsSource = data;
 

stkstute.Visibility = System.Windows.Visibility.Visible;
Storyboard stor = this.Resources["lblAnimation1"] as Storyboard;
 
stor.Completed += new EventHandler(stor_Completed);
stor.SetValue(Storyboard.TargetNameProperty, lblStatus.Name );
stor.AutoReverse = false;
stor.Begin();
 
What's wrong with this code the following error message
'(UIElement.Visibility)' name cannot be found in the name scope of 'MyFirstWPFApp.Window6'
AnswerRe: What's wrong with following code?memberAzim Zahir7-Dec-12 2:45 
I tried your code. It gives the same error. I still have to find the reason. But if you are working with a single label, you can use the following code:
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="lblStatus" Storyboard.TargetProperty="Visibility">
instead of
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="(UIElement.Visibility)">
Hope that solves your problem.
GeneralMy vote of 5membermohammed190.sobhy4-Dec-12 17:22 
thank you
GeneralMy vote of 5memberhari111r18-Nov-12 17:11 
Nice article Smile | :)
GeneralMy vote of 5memberk.shekhar117-Sep-12 21:13 
good explanation
GeneralRe: My vote of 5memberAzim Zahir19-Sep-12 18:01 
Thank you. Smile | :)
Questionhellomemberchilman17-Aug-12 21:09 
Error   1   Circular base class dependency involving 'WpfApplication6.MainWindow' and 'WpfApplication6.MainWindow'  D:\seema\WpfApplication6\WpfApplication6\Window1.xaml.cs    20  27  WpfApplication6
 
this is the error comes in the flag project
please help me
AnswerRe: hellomemberAzim Zahir24-Aug-12 4:07 
Actually the error you said comes when the inheritance list for a class includes a direct or indirect reference to itself. I am not sure why such an error comes in this project. The project works well in VS2010 (.Net framework 4.0.21006). Make sure you are not using the old version of VS and .Net framework.
GeneralMy vote of 5memberraj23karthik14-Aug-12 2:03 
Nice Article Sir Smile | :)
GeneralRe: My vote of 5 [modified]memberAzim Zahir24-Aug-12 4:08 
Thank you. Smile | :)

modified 24-Aug-12 10:28am.

Questionthanksmembernirselickter9-Jul-12 18:10 
i was looking for simple comprehensive article on WPF annimation and find your excellent article.thanks very much for sharing your knowledge.
GeneralRe: thanksmemberAzim Zahir11-Jul-12 15:45 
I am glad that you liked my article. I have posted another article on WPF animation, which I hope you may find useful.
 
Please view this link:
 
Advanced Animations in WPF[^]
GeneralNice articlememberMember 406352627-Jun-12 18:38 
Nice article to understand working of story board
GeneralRe: Nice articlememberAzim Zahir27-Jun-12 21:09 
Thank you very much. Smile | :)
GeneralMy vote of 5, Jai HindmemberDinesh Goziya18-Jun-12 2:44 
My vote of 5, Jai Hind
GeneralRe: My vote of 5, Jai HindmemberAzim Zahir19-Jun-12 2:25 
Thank you. Smile | :)
QuestionEasy To understand and comprehendmemberbabai2811-Jun-12 20:52 
Nice one Azim Sir. I wish we could have more on WPF animation.
 
Best Regards,
Sid
AnswerRe: Easy To understand and comprehendmemberAzim Zahir12-Jun-12 16:21 
Thank you very much. I have posted another article related to WPF Animation.
Advanced Animations in WPF[^]. I hope you would like it. I would like to add other related articles if possible.
GeneralMy vote of 5memberNaresh Goradara27-Apr-12 0:32 
Very nice and easy to understand.
GeneralRe: My vote of 5memberAzim Zahir27-Apr-12 16:50 
Thank you !!!
GeneralMy vote of 5memberDavid Fleming16-Apr-12 13:01 
Very simple. Very well explained. Very easy to follow. Great job!
GeneralRe: My vote of 5memberAzim Zahir16-Apr-12 19:51 
Thank you Smile | :)
GeneralMy vote of 5memberabakwaman15-Apr-12 23:42 
Very fine put me on the right track Thanks.!!!
GeneralRe: My vote of 5memberAzim Zahir16-Apr-12 19:52 
Thank you Smile | :)
GeneralMy vote of 5memberversion_2.012-Apr-12 23:32 
Good one sir..
GeneralRe: My vote of 5memberAzim Zahir13-Apr-12 2:19 
Thank you Smile | :)
GeneralRe: My vote of 5memberMember 78165463-Jan-13 18:14 
good...
QuestionThanks!memberAndy Bantly12-Apr-12 4:32 
I'm a C++ veteran if you look at my posted articles here on the site but I am a newbie with WPF and .NET so I appreciate your kind document to explain things that may seem trivial to .NET or WPF veterans.
AnswerRe: Thanks!memberAzim Zahir12-Apr-12 7:48 
Hi Andy. Thanks for the appreciation. I am pleased to know that you found this article helpful. Smile | :)
GeneralMy vote of 5memberMarco Cordini11-Apr-12 20:10 
You save my Life Smile | :)
GeneralRe: My vote of 5memberAzim Zahir11-Apr-12 22:09 
Thank you Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130617.1 | Last Updated 13 Apr 2013
Article Copyright 2012 by Azim Zahir
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid