Silverlight Animations with XAML & 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 the Getting Started Lesson 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 the next few 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 the 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.