One way to do animations in Silverlight is to make gradual changes to dependency properties. Although this is powerful and convenient, it lacks in control. For example, developing a game with Silverlight may require complex movements of “bad guys” and other background elements that are not well suited for the property-based animation.
The alternative is frame-based animation. That is, every frame some change is applied to an element (such as the attached Canvas.Left and Canvas.Top properties, effectively moving the element around the containing canvas).
How should this be handled in Silverlight? How would we get a notification for every frame?
The most obvious solution is to use a DispatcherTimer object. Here’s a simple example:
DispatcherTimer timer;
public MainPage() {
InitializeComponent();
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(20);
timer.Tick += OnMove;
timer.Start();
}
The OnMove handler does all the changes required for some animation. Although this works, it’s difficult to set the “correct” timeout for the timer. It depends on the desired “frame rate”. In this example, it’s 1000/20=50 frames per second. This may be too much or too little, but worse than that, it’s unsynchronized with Silverlight’s updates (usually 60 fps but can be modified).
There is a better, more elegant way: set up a regular Storyboard that has a duration of zero and handle the Completed event. The handler will be called “immediately”, or more accurately, when Silverlight wants to update the display. This would be a good time to do those updates. Here’s an example:
<UserControl.Triggers>
<EventTrigger RoutedEvent="Control.Loaded">
<BeginStoryboard>
<Storyboard x:Name="move" Duration="0:0:0" Completed="Move_Completed" />
</BeginStoryboard>
</EventTrigger>
</UserControl.Triggers>
Note the zero duration and the event handler. Inside the Completed handler, a call must be made to the Storyboard’s Begin method to “restart” the animation:
There is a third way: using the CompositionTarget.Rendering static event. This is perhaps the simplest of them all – it’s called before Silverlight renders the next frame. Just put whatever needs to be updated in that handler and be done with it.
Happy animations!