Silverlight Animations with XAML & Code
Before we start looking at animating our User Controls with code, let's take a few minutes to see how XAML based animations work. You can think of using XAML Storyboards as the equivalent of doing your tweens on the timeline directly instead of coding an onEnterFrame() or setInterval() event. In fact, a similar interface to the Flash timeline can be found in Expression Blend for creating Storyboards visually using the animation timeline and KeyFrames.
Here is the sample flash movie we will be recreating in Silverlight using XAML storyboards and coded events.
The steps taken in Flash to create the above movie were:
- Create a new Flash Project with a script layer and single frame.
- Create a movieClip named dot with its registration in the center.
- Export the dot MovieClip for ActionScript.
- Add a KeyFrame in dot's timeline at frame 40.
- Shape tween over the next 20 frames to drop the dot and fade it out
- On frame 60, have dot remove itself with removeMovieClip(this);
- Write some code in the script layer on the main stage like this:
This is a great example to duplicate in Silverlight to show how to mix traditional XAML animations and procedural code. We'll use XAML to duplicate our timeline tweens in Flash and C# procedural code to duplicate our event handlers and dynamic visuals. Let's get started.
In Visual Studio, create a new Silverlight Project called Lesson02_a. After you accept the hosting option, you'll see App.xaml and Page.xaml with their respective code behind files ready to go. Since we will be creating our visual content in a separate User Control (just as dot isn't a visual on the stage but a MovieClip defined in the Flash Library), the only changes you need to make in Page.xaml for this project is to switch the default Grid tag to a Canvas tag and style the background color and size to whatever you wish. You will also want to add a Loaded event handler to Page.xaml's User Control tag up top and let Visual Studio create the function stub for you by pressing Tab while typing it. Your adjusted Page.xaml should now look something like this:
Add a new User Control to our Silverlight Project (In the Solution Explorer, right click on Lesson02_a > Add > New Item > Silverlight User Control) and name it Dot.xaml.
As we did in Lesson 01 for the Ball.xaml User Control, change Dot.xaml's LayoutRoot tag type from Grid to Canvas and remove the background color. If we also clear out the Width and Height property from the top User Control Tag, we will be left with a Silverlight User Control that looks and acts similar to an empty MovieClip. Let's next add an Ellipse shape in Dot.xaml named ellipse with the same properties as our original Flash movieClip dot. So far, Dot.xaml should look like this:
At this point, you can right click on Dot.xaml in the Solution Explorer and choose to Open in Blend... if you want to visually create the XAML animation. I created a basic animation that would move the dot down while reducing its opacity, but any Storyboard you wish to create that will move the dot's location and fade it to zero opacity will do. Here is what my finished Blend screen looks like:
As you create your animation in Blend, the Storyboard definition is created in the XAML page as shown below. A couple things to point out. My Storyboard is named sbDrop, so that is how I will address it from code. Also, this storyboard has only been defined. It has not been given any command as to when it should execute. So to solve that, let's add a Loaded event handler in the Dot.xaml User Control as we did previously. And just as our Flash MovieClip had a line of code to run when it reached the end of its animation (the code that would remove the movieClip from the screen to clear up memory), we can add a Completed event handler to our time based sbDrop storyboard in Silverlight. Don't forget to hit Tab while scripting so Visual Studio can create the stub code for you in the Code Behind page.
Our Dot.xaml file should look something to this:
Press F7 to go to the code behind file Dot.xaml.cs and let's add some code to our User Control Loaded and Storyboard Completed event handlers. We want sbDrop to start playing as soon as the control loads, so we add this line of code here:
But how do we remove the User Control once its animation is completed? We don't want to leave every User Control we've added on the screen once they've played out their animation or we will start noticing the same memory drain we would notice in Flash. However, the equivalent one line statement may not be as obvious in C#. The reason for this is that many traditional developers may not consider it proper coding practice to let children (the User Controls or MovieClips) remove themselves directly as we experienced developers have grown accustom to in Flash. But rather, the reasoning goes, the dependent User Control or movieClip should raise an event to their parent container (the LayoutRoot canvas in Page.xaml in our example) and have the parent manage the disposal. We will let others debate the pros and cons of these different approaches, but if you want to know how to duplicate removeMovieClip(this) in Silverlight from within Dot.xaml.cs directly when the sbDrop Storyboard is completed, you can do it this way:
This only works when we are correct in assuming that the Parent of this instance of Dot is a Canvas. Since we are adding the dots in Page.xaml.cs to the LayoutRoot Canvas as visual children, this one line of code works great. There are no dependencies or business logic to these graphics. They exist simply to carry out their basic animation and disappear. Therefore, many of us coming from Flash should feel comfortable with this approach. However, for more complex animations where multiple dependencies between children may exist or where the visuals are coupled to data that may be lost or orphaned, I would suggest a more canonical C# eventing solution.
All we need to do now is add the mouse move handler on Page.xaml. If you recall, we should have already added the Loaded event in the top User Control tag of Page.xaml so our code behind file should have the stub ready for us. The logic is almost identical to what we covered in Lesson01 as you can see here:
Press F5 to run it and you should see it work like so.
Improving the Code
Although we have duplicated the experience in Silverlight, the lack of ability to type _x or _y against our User Controls can start feeling very cumbersome. Here is a work around that anyone coming from Flash will absolutely love.
Go back into your Dot.xaml.cs file and add the following public variables to your class definition like so:
You will see this X and Y definition added to every User Control we create where we need to position them through code. You should become very familiar with them over these 10 lessons!
This defines an X and Y property for your Dot.xaml User Control that sets the Canvas.Left and Canvas.Top dependency properties indirectly in the getters and setters. So you can now update your positioning code in Page.xaml.cs to the more familiar:
Finally, here is an updated Silverlight sample that uses the same logical code, but has a richer animation and design in the XAML. It is included in the download files below for your comparison.
Now that we've seen how traditional Storyboard's work, In our next lesson we're going to see how we can start duplicating the onEnterFrame() functions that play such a big part of custom animations in Flash.