Silverlight

Create Animations with XAML and Expression Blend

Lawrence Moroney

This article discusses:
  • Basic and combined transformations
  • Using triggers and events
  • Linear and discrete key frame animation
  • Animation with Expression Blend
This article uses the following technologies:
Silverlight 2, Expression Blend

This article is based on a prerelease version of Silverlight 2. All information herein is subject to change. This article is adapted from the book Introducing Microsoft Silverlight 2, 2nd Edition by Laurence Moroney (Microsoft Press, 2008).

Contents

Transformations
Rotating with the RotateTransform Property
Scaling with the ScaleTransform Property
Moving an Object with the TranslateTransform Property
Skewing an Object with the SkewTransform Property
Define Transforms with MatrixTransform
Combining Transformations
Animation
Using Triggers and Event Triggers
Using BeginStoryboard and Storyboard
Defining the Animation Parameters
Targeting the Animation
Setting Animation Properties
Setting the RepeatBehavior Property
Animating a Value with DoubleAnimation
Animating a Color with ColorAnimation
Animating a Point with PointAnimation
Using Key Frames
Using Linear Key Frames
Using Discrete Key Frames
Using Spline Key Frames
Animation and Expression Blend
Conclusion

One of the neat things about XAML is that you can not only declare your objects using an XML syntax, but that you can define transformations to apply to these objects in the same way. You don't need to be a programmer to rotate, move, and skew your objects. Also, XAML can be used to describe how you can animate your object, with an animation being defined as changing properties on the object over time. First I'll look at transforms. Later, I'll add them to timelines to animate your Silverlight™ content.

Transformations

In the field of graphics, a transform defines how to map points from one coordinate space to another. This is typically described using a transformation matrix, a special mathematical construct that allows for simple mathematical conversion from one system to another. Silverlight XAML abstracts this matrix and supports four set transformations for rotation, scaling, skewing,and translation (movement). Silverlight XAML also has an additional special transformation type that allows you to define and implement your own matrix, which you can then use to combine transformations.

Transformations are applied using transform properties. There are several different types of transform properties, which are applied to different object types.

Thus, when using a Brush type, you define your transformation in different ways. One is to use the Brush.Transform property when you want to affect the brush's content (if you want to rotate an image before using it in an ImageBrush, for example). Another way is to use the Brush.RelativeTransform property, which allows you to transform a brush using relative values (something you might do if you are painting different areas of different sizes using the same brush, for example).

When using a Geometry type, you apply a simple transform using the Geometry.Transform property. Keep in mind, however, that this type does not support relative transforms.

Finally, when using a UI element, you specify the transformation to use with the RenderTransform property. If you are transforming an ellipse, for example, you'll use the Ellipse.RenderTransform to define the desired transform.

Rotating with the RotateTransform Property

RotateTransform allows you to rotate an element by a specified angle around a specified center point. You set the angle of rotation by using the Angle property to set the number of degrees that you want to rotate the item. To orient yourself, consider the horizontal vector pointing to the right to be 0 degrees, and rotation takes place clockwise, so the vertical vector pointing down is the result of a 90-degree rotation.

You set the center of transformation using the CenterX and CenterY properties to specify the coordinates of the pivot. These default to 0.0, which makes the default rotation pivot the upper-left corner of the container.

In this example XAML, a TextBlock is rotated using a RenderTransform that contains a RotateTransform specifying a 45-degree rotation:

<TextBlock Width="320" Height="40" 
  Text="This is the text to rotate" TextWrapping="Wrap"> 
  <TextBlock.RenderTransform> 
    <RotateTransform Angle="45" /> 
  </TextBlock.RenderTransform> 
</TextBlock>

As you can see in Figure 1, the text is being rotated around a center point at (0,0)—at the upper-left corner of the screen.

fig01.gif

Figure 1 Using the RotateTransform Property

This XAML shows how to use CenterX and CenterY to rotate around a different point. In this case, the rotation is done around the (100,200) point:

<TextBlock Width="320" Height="40" 
  Text="This is the text to rotate" TextWrapping="Wrap" > 
  <TextBlock.RenderTransform> 
    <RotateTransform Angle="45" CenterX="100" CenterY="200" /> 
  </TextBlock.RenderTransform> 
</TextBlock>

Scaling with the ScaleTransform Property

The ScaleTransform property is used to change the size of an object based on the horizontal axis, the vertical axis, or both axes. When scaling an object, you need to specify at least one of the axes around which you want to scale, and by how much you want to scale against that axis.

You use the ScaleX property to scale the object on the horizontal axis, the x-axis, and the ScaleY to scale it on the vertical axis, the y-axis. These are set to a double value, which represents the value by which you multiply the object's current size on the specified axis. Therefore, values greater than 1 will stretch the object by that multiple. For example, using a ScaleX value of 2 will double the size of the object horizontally. Values less than 1, but greater than 0, will shrink the object. Using a setting of 0.5, for instance, will reduce the size of the object by half along the specific dimension.

For example, this XAML creates a red rectangle 96 pixels wide by 88 pixels high:

<Rectangle Fill="#FFFF0404" Stroke="#FF000000" 
  Width="96" Height="88" 
  Canvas.Left="112" Canvas.Top="72" />

Figure 2 demonstrates what this object looks like when it is rendered in Silverlight.

fig02.gif

Figure 2 Rendering the Rectangle

To apply a ScaleTransform to this object, you use a RenderTransform and specify the transform to be a ScaleTransform. Here's the XAML:

<Rectangle Fill="#FFFF0404" Stroke="#FF000000" 
  Width="96" Height="88" Canvas.Left="112" Canvas.Top="72"> 
  <Rectangle.RenderTransform> 
    <ScaleTransform ScaleX="2" /> 
  </Rectangle.RenderTransform> 
</Rectangle>

If you're coding along at home, you'll see that the rectangle increased in size horizontally to the right using this ScaleTransform. This was because the center of scaling was not specified. You can specify it with the CenterX property for horizontal scaling or the CenterY property for vertical scaling. These specify the coordinate of the center of scaling. Note that this coordinate is relative to the upper-left corner of the rectangle. Also, the coordinate default is 0, meaning that scaling will take place to the right on the horizontal axis and downward on the vertical axis.

If you set the CenterX property to a positive value (for example, 50), the scaling will be around the X point, 50 pixels to the right of the leftmost side of the rectangle. This will make it look like the rectangle has moved a number of pixels to the left of the one where the CenterX hasn't been changed (the number depends on the size of the scaling factor). This is because the stretching is centered on that point, pushing the left side of the rectangle to the left as well as pushing the right side to the right. You'll get similar effects by setting the ScaleY and CenterY values in the same way:

<Rectangle Fill="#FFFF0404" Stroke="#FF000000" 
  Width="96" Height="88" 
  Canvas.Left="80" Canvas.Top="80"> 
  <Rectangle.RenderTransform> 
    <ScaleTransform ScaleX="2" 
      CenterX="50"/> 
  </Rectangle.RenderTransform> 
</Rectangle>

Moving an Object with the TranslateTransform Property

A translation is a transform that moves an object in a two-dimensional plane from one position to another. It is defined by setting up vectors that define the object's motion along its x- and y-axes. These are set using the X and Y properties on the transform. To move an item two units horizontally (meaning it will move to the right), you set the X property to 2. To move it to the left, use a negative value, such as -2. Similarly, to move an object vertically, you would use the Y property, and positive values will cause the object to move down the screen, whereas negative values will move it up the screen.

Here's an example of a translate transform that moves the position of the red rectangle that we've been looking at by specifying X and Y values that move it up and to the left. These values effectively make up a vector that determines the transform:

<Rectangle Fill="#FFFF0404" 
  Stroke="#FF000000" 
  Width="96" Height="88" 
  Canvas.Left="80" Canvas.Top="80"> 
  <Rectangle.RenderTransform> 
    <TranslateTransform X="-50" Y="-50"/> 
  </Rectangle.RenderTransform> 
</Rectangle>

See the results of this in Figure 3. The rectangle has moved upward and to the left relative to its specified position, as compared to the position of the rectangle in Figure 2.

fig03.gif

Figure 3 Using the TranslateTransform Property

Skewing an Object with the SkewTransform Property

Skewing an object involves changing it in a progressive, uniform manner along an axis. This has the effect of turning a square or rectangle into a parallelogram. This visual effect is useful in creating the illusion of depth on a two-dimensional surface.

You can apply a skew at a certain angle on either the x- or y-axis and around a center point. These can, of course, be combined so that you can skew on both axes at the same time. The following XAML skews our rectangle on the x-axis by 45 degrees:

<Rectangle Fill="#FFFF0404" Stroke="#FF000000" 
  Width="96" Height="88" 
  Canvas.Left="80" Canvas.Top="80"> 
     <Rectangle.RenderTransform> 
       <SkewTransform AngleX="45"/> 
     </Rectangle.RenderTransform> 
   </Rectangle>

You can see the result in Figure 4.

fig04.gif

Figure 4 Skewing the Rectangle with SkewTransform

Skewing is useful for simulating three-dimensional effects in graphics. For example, you can apply SkewTransform to three adjacent rectangles—two skewed on the x-axis and one on the y-axis—to create an illusion of a three-dimensional perspective (see Figure 5).

fig05.gif

Figure 5 Simulating Perspective with Three Skewed Rectangles

Define Transforms with MatrixTransform

All transformations, at their heart, are performed by multiplying the coordinate space of the object by a transformation matrix. Each of the transforms that you've seen so far is a well-known and well-defined transform. Matrix mathematics and how transforms are implemented are beyond the scope of this article, but for the sake of syntactic completeness, I'll look at how you can define them in Silverlight XAML.

Note that the matrix used in the MatrixTransform is an affine matrix, which means that the bottom row of the matrix is always set to (0 0 1), and as such you set only the first two columns. These are set using the transform's Matrix property, which takes a string containing the first two rows of values separated by spaces:

<Rectangle Fill="#FFFF0404" 
     Stroke="#FF000000" 
     Width="96" Height="88" 
     Canvas.Left="80" Canvas.Top="80"> 
     <Rectangle.RenderTransform> 
       <MatrixTransform Matrix="1 0 1 2 0 1"/> 
     </Rectangle.RenderTransform> 
   </Rectangle>

The impact of the transform using this matrix is to render a combined stretched and skewed rectangle.

Combining Transformations

As you saw in the previous example, you can create a complex transformation by using a transformation affine matrix and specifying that using the MatrixTransform type. However, if you aren't an expert in matrix mathematics, another technique for using transforms is to combine them by means of the TransformGroup element. This simply allows you to specify multiple transforms, and the combined effect of each will be applied to the object. Here's an example:

<Rectangle Fill="#FFFF0404" Stroke="#FF000000" 
  Width="96" Height="88" 
  Canvas.Left="80" Canvas.Top="80"> 
  <Rectangle.RenderTransform> 
    <TransformGroup> 
      <ScaleTransform ScaleX="1.2" ScaleY="1.2" /> 
      <SkewTransform AngleX="30" /> 
      <RotateTransform Angle="45" /> 
    </TransformGroup> 
  </Rectangle.RenderTransform> 
</Rectangle>

This example combines a ScaleTransform that increases the size of the shape on both axes by 20 percent, with a 30-degree skew on the x-axis and a rotation of 45 degrees.

The word animation literally means "imparting life onto something." Hence, with animation you can bring your creations to life by changing the attributes of your objects, such as their color, size, opacity, and other properties, over a period of time or in response to user actions.

In XAML, you animate an item by changing one or more of its properties over time. This time is defined using a timeline. For example, to move an item across the screen in five seconds, you'd specify a five-second timeline that animates the Canvas.Left property from 0 to the width of the screen. In the next sections, I'll discuss each type of animation available, as well as the difference in animating these properties using key frames.

Before you look into the different animation types, you should know that there is a framework around animations that involves Triggers, EventTriggers, and Storyboards. First, however, I'll take a look at these basic concepts and then examine the different animation types in more detail.

Using Triggers and Event Triggers

Animations in Silverlight take place in response to an event, which is defined using a trigger. At present, there is only one trigger type supported in Silverlight XAML, the EventTrigger. Each UI property has a Triggers collection that is used to define one or more triggers (meaning one or more EventTriggers).

So, the first step in adding an animation to an element is to define its Triggers collection; then you'll need to add at least one EventTrigger to the collection you've created. For example, if you are animating a rectangle, the first step—specifying the Triggers collection—will look like this:

<Rectangle x:Name="rect" Fill="Red" 
  Canvas.Top="100" Canvas.Left="100" 
  Width="100" Height="100"> 
  <Rectangle.Triggers> 
  </Rectangle.Triggers> 
</Rectangle>

Next, you will need to define an EventTrigger to add to this collection. On this EventTrigger, you will use the RoutedEvent property to specify which event the animation runs in response to. Note that RoutedEvent only supports the Loaded event.

To implement an animation that will begin when the rectangle is loaded, you would specify the EventTrigger as follows:

<EventTrigger RoutedEvent="Rectangle.Loaded"> 
</EventTrigger>

The XAML snippet to run this animation looks like this:

<Rectangle x:Name="rect" Fill="Red" Canvas.Top="100" 
  Canvas.Left="100" Width="100" Height="100"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>

The next step is to define the animation that you want to use. Animations are contained within Storyboards.

Using BeginStoryboard and Storyboard

BeginStoryboard is a trigger action that contains a Storyboard object. Storyboard objects contain the animation definitions. When you define an animation, you simply embed these objects within the EventTrigger definition. The following code shows how this would be accomplished using my rectangle example:

<Rectangle x:Name="rect" Fill="Red" 
  Canvas.Top="100" Canvas.Left="100" 
  Width="100" Height="100"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>

Defining the Animation Parameters

Now that the framework for the animation is set up, you can specify the animation that you want to perform. At its most basic level, animation defines changing a property over time. You can animate three different property types. Each of these property types is animated from a value specified in the From attribute (or its current value if this is not set) either to a value specified in the To attribute or by a value specified in the By attribute.

Double Types These are animated using the DoubleAnimation or DoubleAnimationUsingKeyFrames. This method is used to animate properties that contain a double value—for example, dimensions such as Canvas.Left or visual attributes such as Opacity.

Point Types These are animated using a PointAnimiation or PointAnimationUsingKeyFrames type. This particular method is used to animate properties that contain a Point value, such as line segments or curves that are defined using points.

Color Types These are animated using a ColorAnimation or Color­AnimationUsingKeyFrames type. This method is used to animate properties that contain a color value—the background or stroke of an element, for instance.

Targeting the Animation

To define which object you want to apply the animation to, you use the Storyboard.TargetName property on these animation types, and you need to pass it the name of the object in question, which is set on the object using the x:Name property. Additionally, you specify the property that will be animated using the Storyboard.TargetProperty. Note that if you are specifying a complex or attached property (such as Canvas.Left), you place it in parentheses. So, for example, to specify a Double animation to target the Canvas.Left of a rectangle named rect, the resulting XAML will look like this:

<DoubleAnimation Storyboard.TargetName="rect" 
  Storyboard.TargetProperty="(Canvas.Left)" />

Setting Animation Properties

To define how long it will take to transition the properties in question from one value to another, you use the Duration property. Note that it is defined in the HH:MM:SS format, wherein a five-second time duration for the animation is specified as 00:00:05, abbreviated to 0:0:5.

<DoubleAnimation Storyboard.TargetName="rect" 
  Storyboard.TargetProperty="(Canvas.Left)" Duration="0:0:5" />

If you do not want the animation to begin right away, you can insert a delay using the BeginTime property, using the same syntax:

<DoubleAnimation Storyboard.TargetName="rect" 
  Storyboard.TargetProperty="(Canvas.Left)" BeginTime="0:0:5" />

You can also tweak the animation behavior by multiplying the duration by a speed ratio. This is achieved using the SpeedRatio property. For example, in the previous case the duration was set to 5 seconds. You can change the speed ratio to make the animation last 10 seconds by setting SpeedRatio to 2, or, alternatively you can speed the animation up to 1 second by setting SpeedRatio to 0.2.

<DoubleAnimation Storyboard.TargetName="rect" 
  Storyboard.TargetProperty="(Canvas.Left)" 
  SpeedRatio="2" Duration="0:0:5" />

Silverlight animation provides the facility to reverse the changes made as part of the animation. For example, if you are moving a double value from 0 to 500 over a specific time frame, an Auto­Reverse will cause the animation to move from 500 back to 0.

Note that if the animation is set to run for 5 seconds as previously, and the AutoReverse is set to true, then the complete animation will take 10 seconds. Following is an example of XAML containing the AutoReverse property:

<DoubleAnimation Storyboard.TargetName="rect"    
  Storyboard.TargetProperty="(Canvas.Left)" 
  AutoReverse="True" 
  Duration="0:0:5" />

Setting the RepeatBehavior Property

When the animation has finished running, you can apply a number of options to control how you want it to behave. You specify these using the RepeatBehavior property. This property can take three different types of values:

  • A time defined in seconds. The timeline will wait for this period and then start the animation again.
  • Repeat behavior set to Forever for constant repetition.
  • A discrete number of repetitions set by specifying a number followed by x. For example, if you want the animation to run three times, you specify the value 3x.

Figure 6 shows the complete XAML for the animated rectangle to move it from 100 to 500 and back to 100 on the x-axis and then repeat that behavior three times:

Figure 6 Reversing and Repeating Animation

<Rectangle x:Name="rect" Fill="Red" 
  Canvas.Top="100" Canvas.Left="100" 
  Width="100" Height="100"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <DoubleAnimation RepeatBehavior="3x"               
            Storyboard.TargetName="rect" 
            Storyboard.TargetProperty="(Canvas.Left)" 
            To="500" Duration="0:0:5" 
            AutoReverse="True" /> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>

Let's look at each of these animation types in a little more detail. First, I'll examine the attributes needed to animate each of the various types, and then I'll address where the associated key frame type of animation fits into the picture.

Animating a Value with DoubleAnimation

The DoubleAnimation object allows you to specify how a double value will change over a specified timeline. The animation is calculated as a linear interpolation between the property values over time.

When animating a double, you specify the value at the start of the animation using the From value and then change it to either the To value, which is an absolute destination, or the By value, which is a relative destination. For example, if you are moving the Canvas.Left property of an item from 100 (near the left of the screen) to 500, you can set From to 100 and To to 500, or By to 400. Note that if you set both, the To property takes precedence and the By property is ignored. Also, if the rectangle is already located at the desired From position, you do not need to specify the From property.

The previous XAML example displayed this behavior. The rectangle is located with a Canvas.Left value of 100, and the DoubleAnimation specifies the To value as 500. Hence, the animation will move the value from 100 to 500, which will cause the rectangle to move across the screen to the right.

Animating a Color with ColorAnimation

ColorAnimation operates in a manner that is similar to DoubleAnimation. You use it to specify how the color value of an element will change over time. The animation is then calculated as a linear interpolation between the color values over the specified time.

When animating a color, you specify the value at the start of the animation using the From property. If you do not specify this, then the current color is used. You specify the desired end color using the To attribute. You can also specify a By attribute, which will provide the end color that is the result of adding the values of the From color (or the starting color) to the By color.

When you animate a color-based property, you do not animate the contents of the property directly, because the content of the property is usually a brush and not a color. So, if you want to animate the fill color of a rectangle, for example, you don't use the rectangle's Fill property as your target. Instead, you specify that you intend to animate the Color property of the SolidBrush that is used to perform the fill.

Figure 7 shows an example of how to animate the color of a rectangle, changing it from black to white over a time duration of five seconds, using a color animation. As you can see in the code, this XAML snippet specifies the Color property of the SolidColorBrush that is filling the shape as its target property. Note that this is the typical XAML syntax used in addressing complex properties like this scenario.

Figure 7 Animating Color Change

<Rectangle x:Name="rect" Canvas.Top="100" 
  Canvas.Left="100" Width="100" 
  Height="100" Fill="Black"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <ColorAnimation Storyboard.TargetName="rect" 
            Storyboard.TargetProperty= 
            "(Shape.Fill).(SolidColorBrush.Color)" 
            To="#00000000" Duration="0:0:5" /> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>

Animating a Point with PointAnimation

To change a value that is defined as a point over time, you use the PointAnimation type. The animation is then calculated as a linear interpolation between the values over the specified time.

In a manner similar to the Color and Double animations, you specify the start value using From and the destination either as a relative direction (using By) or an absolute point (using To). Figure 8 shows an example of how you could animate the end point of a Bezier curve. In this case, the Bezier curve is defined with a start point at (100,100), an end point at (300,100), and a control point at (200,0). An animation is set up to trigger after the path loads, and it animates the end point of the curve (Point2) from (300,100) to (300,600) over a time duration of five seconds.

Figure 8 Animating the End of a Curve

<Path Stroke="Black" > 
  <Path.Data> 
    <PathGeometry> 
      <PathFigure StartPoint="100,100"> 
        <QuadraticBezierSegment x:Name="seg" 
          Point1="200,0" Point2="300,100"  /> 
      </PathFigure> 
    </PathGeometry> 
  </Path.Data> 
  <Path.Triggers> 
    <EventTrigger RoutedEvent="Path.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <PointAnimation Storyboard.TargetName="seg" 
            Storyboard.TargetProperty="Point2" 
            From="300,100" To="300,600" Duration="0:0:5" /> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Path.Triggers> 
</Path>

Using Key Frames

The three animation types that you've just learned about, Color­Animation, DoubleAnimation, and PointAnimation, all work by changing a defined property over time using linear interpolation. For example, if you are moving a double value from 100 to 500 over five seconds, it will increment by 80 each second.

Each of these three animation types can have this transition defined through a set of milestones called key frames. To change the linear behavior of the animation from the starting property to the ending property, you simply insert one or more key frames. Then you define the style of animation that you want between these various points.

Key frames are defined using key times. These are times that are specified relative to the start time of the animation; they also specify the end time of the key frame. So, for instance, if you need a nine-second animation with three evenly spaced key frames, you can specify the first key frame to end at 0:0:3, the second to end at 0:0:6, and the third to end at 0:0:9. Keep in mind that you do not specify the length of the key time—instead, you specify the end time for each key frame.

As another example, consider a Double animation that you want to span half the range of 100 to 500. The animation should move very quickly in the first half and very slowly in the second half. Overall, it will require a six-second total transition. Since 350 is the midpoint between 100 and 500, you would define a key frame to begin at point 350. You'd tell it to go for one second between the start point and the midpoint, using a key time of 0:0:1, and then set a time duration of five seconds between the midpoint and the end point by using a second key time of 0:0:6. Now the item is set to zip across the screen to the midpoint and then it will seem to crawl the rest of the way.

In the previous example, both animated segments will be linearly interpolated. To provide extra flexibility, two other types of key frames are provided: a discrete key frame that instantly jumps the value between the two values, and a spline key frame that moves the value between the first and end points using a quadratic curve to define the interpolation. (In the following sections, you'll look at how to define an animation using key frames for the Double type. Note that the same principles apply for Point and Color animation types.)

To specify key frames, you use the UsingKeyFrames postfix on your animation. That is, to define Double animations and use key frames, you'll use DoubleAnimationUsingKeyFrames on which you specify your target and property (in the same way you use DoubleAnimation). DoubleAnimationUsingKeyFrames contains the key frame definitions. (And as I mentioned earlier, the same applies to PointAnimationUsingKeyFrames or ColorAnimationUsingKeyFrames.)

Using Linear Key Frames

The default method for animation between two property values is linear interpolation in which the amount is divided evenly over time. You can also define linear steps between frames using the LinearKeyFrame type in which linear interpolation is still used, but it is used between key frames, so you can have an acceleration/deceleration effect.

Consider the animation code shown in the first part of Figure 9. Here, a DoubleAnimationUsingKeyFrames is used, and it defines two key frames. One defines a linear interpolation between 0 and 300 for Canvas.Left changes over one second, and the next defines a linear interpolation between 300 and 600 for Canvas.Left changes over eight seconds. This has the effect of making the rectangle move quickly to the halfway point, then slowly the rest of the way across. Similar principles apply for the LinearPointKeyFrame and LinearColorKeyFrame.

Figure 9 Animation with Key Frames

Linear Interpolation

<Rectangle Fill="#FFFF0000" Stroke="#FF000000" 
  Width="40" Height="40" 
  Canvas.Top="40" x:Name="rect"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <DoubleAnimationUsingKeyFrames 
            Storyboard.TargetName="rect" 
            Storyboard.TargetProperty="(Canvas.Left)" > 
            <LinearDoubleKeyFrame KeyTime="0:0:1" Value="300" /> 
            <LinearDoubleKeyFrame KeyTime="0:0:9" Value="600" /> 
          </DoubleAnimationUsingKeyFrames> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>

Discrete Key Frames

<Rectangle Fill="#FFFF0000" Stroke="#FF000000" 
  Width="40" Height="40" 
  Canvas.Top="40" x:Name="rect"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <DoubleAnimationUsingKeyFrames 
            Storyboard.TargetName="rect" 
            Storyboard.TargetProperty="(Canvas.Left)" > 
            <DiscreteDoubleKeyFrame KeyTime="0:0:1" Value="300" /> 
            <DiscreteDoubleKeyFrame KeyTime="0:0:9" Value="600" /> 
          </DoubleAnimationUsingKeyFrames> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>

Using Discrete Key Frames

If you want to change the property from one value to another and not use linear interpolation, you can use a discrete key frame. This causes the object to jump to the value at the specified key frame time.

The second part of Figure 9 shows the same example as the previous one, except that it uses a discrete key frame. At one second into the animation, the rectangle will jump halfway across the screen. Then at nine seconds into the animation, it will jump to the right of the screen. Note that similar principles apply for the DiscretePointKeyFrame and DiscreteColorKeyFrame.

Using Spline Key Frames

To change the property from one value to another using a curved value that provides for acceleration and deceleration, you use a spline key frame. To do this, first you define a quadratic Bezier curve and then the speed of the property as it moves from one value to another is determined by a parallel projection of that curve.

If this is hard to visualize, consider the following scenario: the sun is right overhead, and you hit a baseball into the outfield. You look at the shadow of the ball. As it is climbing into the air, the movement of the shadow appears to accelerate. As it reaches its apex, you'll see the shadow decelerate. As the ball falls, you'll see the speed of the shadow accelerate again, until either it is caught or it hits the ground.

Imagine your animation in this case is the ball's shadow and the spline is the curve of the baseball. You define the trajectory of the baseball, a spline, using a KeySpline. The KeySpline defines control points for a quadratic Bezier curve. It is normalized so that the first point of the curve is at 0, and the second is at 1. For a parabolic arc, which is the trajectory the baseball would follow, the KeySpline will contain two comma-separated normalized values.

To define a curve such as the flight of a baseball, you can specify the spline using a KeySpline such as 0.3,0 0.6,1. This defines the first point of the curve at (0.3,0) and the second at (0.6,1). This will have the effect of making the animation accelerate quickly until approximately one-third of the movement of the baseball is complete; then it will move at a uniform speed until approximately two-thirds of the ball's trajectory is reached; and then it will decelerate for the rest of the flight of the animated baseball, as the animation simulates the ball's fall to earth.

Figure 10 shows an example of using a KeySpline to define the spline for this simulation using DoubleAnimationUsingKeyFrames. This example animates the ellipse so that it moves across the screen in a manner similar to the shadow of a baseball, as if you were above the baseball looking down toward the ground as the ball flies through the air.

Figure 10 Defining a Spline with KeySpline

<Ellipse Fill="a#FF444444" Stroke="#FF444444" 
  Width="40" Height="40" 
  Canvas.Top="40" x:Name="ball"> 
  <Ellipse.Triggers> 
    <EventTrigger RoutedEvent="Ellipse.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <DoubleAnimationUsingKeyFrames 
            Storyboard.TargetName="ball" 
            Storyboard.TargetProperty="(Canvas.Left)" > 
            <SplineDoubleKeyFrame KeyTime="0:0:5" 
              KeySpline="0.3,0 0.6,1" Value="600" /> 
          </DoubleAnimationUsingKeyFrames> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Ellipse.Triggers> 
</Ellipse>

Animation and Expression Blend

Animation can be defined graphically in Expression Blend™. This generates the XAML for you to perform the animation, providing the different types of animation for you automatically.

When using Expression Blend, select Animation Workspace from the Window menu. This will give you the tools to graphically design timelines, and when you edit the properties that you want changed using the visual editor, then the XAML code for the animation will be generated.

At the bottom of the screen, you can see the Objects and Timeline view. This allows you to add a timeline and then visually add key frames. To add a new timeline, click the + button in the Objects and Timeline view.

When you click the + button, you'll see a Create Storyboard dialog box that asks you for the name of the storyboard to create. In this case, I've changed the default name from Storyboard1 to Timeline1 and cleared the Create as Resource checkbox.

When using Expression Blend, you can create an animation at the Canvas level or as a Resource. In the case of the former, animations then run in response to triggers on the canvas. Following is an example of the XAML created by Blend from the Create Storyboard dialog box, where the user specified that they did not want to create the animation as a Resource:

<Canvas.Triggers> 
  <EventTrigger RoutedEvent="Canvas.Loaded"> 
    <BeginStoryboard> 
      <Storyboard x:Name="Timeline1"/> 
    </BeginStoryboard> 
  </EventTrigger> 
</Canvas.Triggers>

Note that if the user checked the Create as Resource checkbox, then the Storyboard would be created within <Canvas.Resources> and you would have to run it from JavaScript.

The Objects and Timeline view will change to show the timeline that you've just created. You can see the timeline at the bottom of Figure 11.The vertical line at time 0 that you see in the timeline denotes the current time. (In Expression Blend, this line will be yellow.) To add a key frame, you simply drag this line to the time where you want a key frame and click the Record Keyframe button. This button is located just above the timeline to the left of 0:00:000.

fig11.gif

Figure 11 Expression Blend Animation Workspace (Click the image for a larger view)

Drag the line to the four-second mark and add a key frame. You'll see the key frame added as a small oval on the timeline. Now that the timeline is on the four-second frame and you have added a key frame, you can edit the rectangle's color, location, opacity, or shape, and Blend will calculate the correct transformations necessary to facilitate the animation. Finally, you may notice that if you drag the timeline indicator around, you can preview the animation and see how it appears at any particular time.

In this article, I discussed how transformations and animations are defined in Silverlight XAML. I introduced you to different types of transformation used to rotate, scale, or skew an object, as well as to freeform transformations using an affine matrix as applied to a shape. I then offered an overview of animations and showed you how to define an animation to run based on an XAML trigger. You saw how animations change property values over time, and you looked at the XAML types that support animating double, point, and color values. I then explained how to use key frames for finer control over your animations. Finally, I showed you the Expression Blend animation designer so you could see how easily animations can be generated visually using Expression Blend.

Laurence Moroney is a Senior Technology Evangelist with Microsoft, specializing in Silverlight. He is the author of many books on computing topics, including Silverlight, AJAX, Interoperability, and Security. You can find Laurence's blog at blogs.msdn.com/webnext.