Tutorials Books Videos Forums

Change the theme! Search!
Rambo ftw!

Customize Theme


Color

Background


Done

Creating Killer Animations in Code

by kirupa   | filed under Silverlight, WPF, and Blend

This is an archived tutorial from the kirupa.com legacy collection. It covers software that may no longer be available, but it is kept online because the ideas still hold up.

In Silverlight and WPF, there are several ways you can create animations. One way that has been covered before on this site involves creating a storyboard and using Expression Blend to visually create your animation. This approach is great for majority of all animations you would ever want to create. There are exceptions where this solution doesn't work as well as you would like.

Animations that are more random or will have a certain degree of variability don't fit well inside the box defined by Storyboards. For example, here is an example of an animation where the circles move around a centerpoint with a random speed each time you refresh the page:

[ the circles...they are spinning! ]

Something similar to what you see above works best when created in code, and this tutorial will show you one way of going about doing that.

Drawing a Circle

Before we write some code and perform other acts of magic, we first need to create a new project and draw a circle. The following steps will help you to do that:

  1. First, go ahead and launch Expression Blend and create a new Silverlight 3 Application + Website project. Give your application any name you want as well.
     
    If you don't have Expression Blend or Silverlight installed, jump over to my Getting Started page to get up and running.

  2. Once your project has been created, you will see a blank design surface where you can draw and do all kinds of things. What we want to do is first draw a circle. From the Tools panel (usually found on the left), click on the Shapes menu (usually defined by a rectangle) and select the Ellipse tool:

[ expand the Shapes menu to select the Ellipse ]

  1. Once you have selected the Ellipse tool, your Tools menu will display the Ellipse tool by default instead of the Rectangle you had earlier. Simply double click on the Ellipse tool to insert a circle into your design surface.

[ insert an Ellipse - by default, it will be a circle ]

  1. The circle that you just inserted probably doesn't look very pretty, so feel free to make some tweaks as you wish using the properties found in the Propeties Panel's Brushes category:

[ my circle is blue and partially transparent ]

  1. At the very least, make sure your circle is a blue-ish color so that it is visible and kinda matches the screenshots. As you can tell from the screenshot of my Brushes category, I made my circle a light blue with a 50% opacity and no Stroke. The final result is as follows:

[ what my circle looks like ]

Ok, now that our circle is finished, an important first step has been completed. The next step is to make our circle into something that can store some code, and we'll look at the savory details in the next section.


In the previous section, you created your project and drew a circle. In this page, let's pick up from where we left of and make our circle a little bit more useful.

Making our Circle into a UserControl

Our circle right now looks pretty, but it isn't very useful. It is merely a primitive shape of type Ellipse:

[ the shapes (much like goggles)...do nothing! See funny clip here ]

 What we want to do is convert our circle into something that can contain code and be something more than just a shape. That something is a UserControl. If you are familar with Flash, think of a UserControl as a MovieClip.

To convert your circle into a UserControl, select the circle with your mouse and press F8 or go to Tools | Make into UserControl:

[ press F8 or go to Tools | Make Into UserControl ]

Once you have called the Make Into UserControl command, the Make Into UserControl dialog will appear. In this dialog, you get the opportunity to name your UserControl. Give your UserControl the name BlueCircle:

[ give your UserControl the name BlueCircle ]

Click OK to close this dialog and to create the new UserControl with the name BlueCircle. Many things will have happened behind the scenes once you converted your shape into a UserControl, but the most noticeable is that your circle now lives in its own XAML file called BlueCircle.

You can tell by looking at the list of open documents where you see BlueCircle.xaml opened alongside MainPage.xaml:

[ your circle is all grown up now. It is now a UserControl ]

Just for kicks, go ahead and press F5 (Project | Run Project) to see what happens now. After a few seconds, your browser will load, but all you will see is just your blue circle. That's great - there shouldn't be anything else going on. Don't worry, we will fix that up soon.

Changing the Root Layout to a Canvas

Switch back to MainPage.xaml. Take a look at your Objects and Timeline panel and notice that you see your BlueCircle usercontrol now displayed there:

[ what was a shape before is now a UserControl whose type is BlueCircle ]

That's not the only thing I wanted you to notice though. Notice that your BlueCircle usercontrol is nested under LayoutRoot. LayoutRoot currently is a Grid layout panel. While for most applications, using Grids is good, for what we are going to do - programmatically move things around, a Grid is not what we want.

What we need is the more basic Canvas. To change your LayoutRoot to a Canvas, right click on LayoutRoot, and from the menu that appears, go to Change Layout Type | Canvas:

[ change from a Grid to a Canvas ]

Once you have done this, your LayoutRoot layout panel will now be a Canvas. You can tell by having LayoutRoot selected and looking in your Properties Inspector, directly below the element name, where the type of the element is displayed:

[ LayoutRoot is now a Canvas ]

I will explain later why we had to make this change, but for now, let's proceed to the next step - which is, adding the code. That will be done in the next section.


In the previous section, you converted your circle into a UserControl and made sure its parent layout container was a Canvas. All of that is just the preparation for what we are about to do here. Read on!

Adding the Code to Make the Circle Move

The next step is to add some code to make your circle actually move. From your Projects panel, expand BlueCircle.xaml by clicking on the tiny arrow found left of it and open BlueCircle.xaml.cs that appears nested directly under it by double-clicking on it:

[ open BlueCircle.xaml.cs ]

When you double-click the BlueCircle.xaml.cs file, Blend will open that file in its code-editor where you can write and edit code using a lot of the cool functionality that you would expect from a code-editing environment.

If I ignore the using statements and namespace declaration, the code that you see currently will look as follows:

public partial class BlueCircle : UserControl
{
  public BlueCircle()
  {
  // Required to initialize variables
  InitializeComponent();
  }
}

What you are going to do next is copy and paste some code. Copy the following code and paste it directly over the entire chunk of code defined in the public BlueCircle() block:

private static Random randomMain = new Random();
private double angle;
private double speed;
private double xPos;
private double yPos;
public BlueCircle()
{
  // Required to initialize variables
  InitializeComponent();
  this.Loaded += new RoutedEventHandler(CircleLoaded);
}
void CircleLoaded(object sender, RoutedEventArgs e)
{
  xPos = Canvas.GetLeft(this);
  yPos = Canvas.GetTop(this);
  speed = .01 + randomMain.NextDouble();
  if (DesignerProperties.GetIsInDesignMode(this) == false)
  {
  CompositionTarget.Rendering += new EventHandler(AnimateCircle);
  }
}
void AnimateCircle(object sender, EventArgs e)
{
  angle += speed/10;
  Canvas.SetTop(this, yPos + 50 * Math.Sin(angle));
  Canvas.SetLeft(this, xPos + 50 * Math.Cos(angle));
  if (angle >= 2 * Math.PI)
  {
  angle = 0;
  }
}

After you have pasted that code, there is one more copy/paste action that you need to do. In the list of using statements you see at the top of your code file, paste the following directly below using System.Windows.Shapes:

using System.ComponentModel;

Once your code has been pasted in, your BlueCircle.xaml.cs file will basically look as follows:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
namespace <YourProjectName>
{
  public partial class BlueCircle : UserControl
  {
  private static Random randomMain = new Random();
  private double angle;
  private double speed;
  private double xPos;
  private double yPos;
  public BlueCircle()
  {
  // Required to initialize variables
  InitializeComponent();
  this.Loaded += new RoutedEventHandler(CircleLoaded);
  }
  void CircleLoaded(object sender, RoutedEventArgs e)
  {
  xPos = Canvas.GetLeft(this);
  yPos = Canvas.GetTop(this);
  speed = .01 + randomMain.NextDouble();
  if (DesignerProperties.GetIsInDesignMode(this) == false)
  {
  CompositionTarget.Rendering += new EventHandler(AnimateCircle);
  }
  }
  void AnimateCircle(object sender, EventArgs e)
  {
  angle += speed/10;
  Canvas.SetTop(this, yPos + 50 * Math.Sin(angle));
  Canvas.SetLeft(this, xPos + 50 * Math.Cos(angle));
  if (angle >= 2 * Math.PI)
  {
  angle = 0;
  }
  }
  }
}

It is time to test it out and see how it works. Press F5 (or Project | Run) to load your browser and load your application. If everything went well, you will see your circle slowly moving!

Now that you have a working project, let's next look at why the code works the way it does in greater detail in the next section.


In the previous section, you added some code and got your circle moving when you previewed it. Now comes the really fun part - learning why the various components work the way they do.

Birds Eye View of How Things Work

Before diving into the code, I think it is helpful to look at the bigger picture and how everything works. An animation is nothing more than something changing over a period of time. That something could be a whole host of things, but for this example (and many others), something refers to properties.

Over a period of time, some property changes, and this property change is what we notice. In our example, what properties are changing? Looking at what our animation is doing. It is moving the circle in a circular fashion, and the properties that are changing seem to be horizontal position and the vertical position of the circle:

There are basically two things we are doing in our code:

  1. Setting the properties representing the horizontal and vertical position.

  2. Changing the properties at a given time using some sort of a timer-like mechanism.

At each tick of the clock, we change our properties gradually to give you the illustion of smooth movement. That is, of course, easier said than done. The preceding sentence is what I converted into all the C# code that you copied and pasted earlier. Don't let the volume of the code scare you though, for in the next section, we'll try to make sense of it all.

Looking at the Code

Ok, now that you have a conceptual understanding of what programmatic animations do - change properties over a period of time, let's see how all of that looks translated into code. I'm going to be starting at the top of BlueCircle.xaml.cs and move down.

The first handful of lines are just declaring variables:

private static Random randomMain = new Random();
private double angle;
private double speed;
private double xPos;
private double yPos;

The only thing that I will call out is that our randomMain variable is declared using the static modifier. The reason is that I want to persist only a single Random object throughout this application's life. This has to do with how random numbers are initialized in .NET, but I will delve further into random numbers in a different article sometime in the future.


public BlueCircle()
{
  // Required to initialize variables
  InitializeComponent();
  this.Loaded += new RoutedEventHandler(CircleLoaded);
}

Next up is our BlueCircle constructor. If you are not familiar with what a constructor actually is, I'm going to refer you to my earlier tutorial on Classes. In a nutshell, it is basically the gateway to your code that is provided for you by default.

I added one line to our constructor, and that line is the non-grayed out one you see above. I am associating our UserControl's Loaded event with an event handler called CircleLoaded. Translated into English, when my circle usercontrol loads, I want to the CircleLoaded function to be called.


Speaking of CircleLoaded...

void CircleLoaded(object sender, RoutedEventArgs e)
{
  xPos = Canvas.GetLeft(this);
  yPos = Canvas.GetTop(this);
  speed = .01 + randomMain.NextDouble();
  if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) == false)
  {
  CompositionTarget.Rendering += new EventHandler(AnimateCircle);
  }
}

...let's look at it next. The CircleLoaded method, like I mentioned earlier, gets called when the Loaded event is fired. The first two variables initialize our horizontal and vertical positions that we declared earlier as xPos and yPos:

xPos = Canvas.GetLeft(this);
yPos = Canvas.GetTop(this);

I am getting the x and y positions of this user control by using the Canvas.GetLeft and Canvas.GetTop properties. This is the closest thing to a clean syntax you get in C# for getting an element's position

In the next line, I set the speed of our movement:

speed = .01 + randomMain.NextDouble();

Notice that our static randomMain variable is used to set a really small random number. As you will see shortly, there is a reason why the number is as small as it is.

The next statement block is interesting:

if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) == false)
{
  CompositionTarget.Rendering += new EventHandler(AnimateCircle);
}

This if statement has no bearing on what you see when you test your appllication. This is to ensure that the code I am going to talk about next does not run inside Expression Blend. I will describe the cool feature about this at a later time.

Ok, we have one more line left to describe, and I am going to describe in the next section - that's how important that line is.


In the previous section, I briefly explained how the code works before diving into the code itself. In this page, let's finish explaining the code and wrap any loose ends up.


The line we stopped at in the previous section is the following:

if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) == false)
{
  CompositionTarget.Rendering += new EventHandler(AnimateCircle);
}

If there is one thing you remember from this tutorial it is this - hooking into the Rendering event is one of the best ways to create a loop for an animation that does not block or freeze your application. At every screen refresh, a method that you specify gets called. Needless to say, that method is going to get called a whole lotta times every second.

You access the rendering event as follows:

CompositionTarget.Rendering += new EventHandler(AnimateCircle);

Just like any event you will encounter in .NET, you have to associate it with an event handler that will get called each time the event fires. In our example, that event handler is called AnimateCircle. The AnimateCircle method gets called numerous times each second because the Rendering event fires numerous times each second, so any code that you want to use for simulating your animation, you would want to place inside your AnimateCircle movie clip.


Let's look at our AnimateCircle method next:

void AnimateCircle(object sender, EventArgs e)
{
  angle += speed/10;
  Canvas.SetTop(this, yPos + 50 * Math.Sin(angle));
  Canvas.SetLeft(this, xPos + 50 * Math.Cos(angle));
  if (angle >= 2 * Math.PI)
  {
  angle = 0;
  }
}

The AnimateCircle method is responsible for actually adjusting the x and y positions, and that is done via the Canvas.SetTop and Canvas.SetLeft function. These are the opponents, if you will, of the Canvas.GetTop and Canvas.GetLeft function that you saw earlier.

I am not going to delve into the mechanics of the animation itself, but you can get an overview of the type of animation by looking into the first few non-ActionScript related pages of the Trigonometric Animations tutorial. One thing I mentioned earlier is that our speed value is being set at a very small number. While the number is very small, because we are incrementing the angle variable by the speed property in a method that gets called hundreds of times every few seconds, everything balances out.

Adding More Circles

Currently, you only have one lone circle in your animation. In Blend, make sure MainPage.xaml is currently opened. Select the lone circle usercontrol that you see, copy it by pressing Ctrl + C (or using the right-click menu), and paste it a bunch of times. Your Objects and Timeline panel will look as follows with many instances of your BlueCircle usercontrol displayed:

[ you can never have too many circles...that are blue! ]

On the design surface, feel free to move each circle around, alter its sizes, etc. Be creative. Here is what my design surface looks like:

[ be creative in your placement and look of the circles ]

Because each usercontrol is a self-contained animation with a copy of all of the code that you saw in the preceding pages, simply hitting F5 is all you need to after you paste/rearrange all of the circles to seem them all movie in their own random, circular way.


Conclusion

Well, that is all there is to creating code-based animations in Silverlight and WPF. There basically three things you need to follow:

  1. Ensure your UserControl has fully loaded by hooking up the Loaded event with an event handler.

  2. Inside your Loaded event's event handler, setup the Rendering event and associate that with an event handler that will process the Rendering events.

  3. Place any code that will be responsible for continuously updating the properties that will make up your animation inside the event handler for the CompositionTarget.Rendering event.

  4. Go crazy. Very rarely will you ever have the opportunity to easily combine math with programming to create something beautiful and engaging. Take advantage of these rare moments.

To see how my version looks, as always, you can download the source files from below:


Just a final word before we wrap up. What you've seen here is freshly baked content without added preservatives, artificial intelligence, ads, and algorithm-driven doodads. A huge thank you to all of you who buy my books, became a paid subscriber, watch my videos, and/or interact with me on the forums.

Your support keeps this site going! 😇

Kirupa's signature!

The KIRUPA Newsletter

Thought provoking content that lives at the intersection of design 🎨, development 🤖, and business 💰 - delivered weekly to over a bazillion subscribers!

SUBSCRIBE NOW

Creating engaging and entertaining content for designers and developers since 1998.

Follow:

Popular

Loose Ends

:: Copyright KIRUPA 2026 //--