Channels ▼
RSS

Web Development

Silverlight Animation


Transforms

As you've already learned, Silverlight animations work by modifying the value of a property. Elements have several properties that can be usefully changed. For example, you can use Canvas.Left and Canvas.Top to move an element around. Or, you can alter the Opacity setting to make an element fade into or out of view. However, it's not immediately clear how you can perform more exciting alterations, like rotations.

The secret is "transforms." A transform is an object that alters the way a shape or other element is drawn by shifting the coordinate system it uses. You can use transforms to stretch, rotate, skew, and otherwise manipulate the shapes, images, and text in your Silverlight user interface. Transforms are useful for getting the right shape you want, but they're even more interesting when you're animating. By animating a property in a transform, you can rotate a shape, move it from one place to another, or warp it dynamically.

Table 2 lists the transforms that are supported in Silverlight.

TranslateTransform Displaces your coordinate system by some amount. This transform is useful if you want to draw the same shape in different places. X,Y
RotateTransform Rotates your coordinate system. The shapes you draw normally are turned around a center point you choose. Angle, CenterX, CenterY
ScaleTransform Scales your coordinate system up or down so that your shapes are drawn smaller or larger. You can apply different degrees of scaling in the X and Y dimensions, thereby stretching or compressing your shape. ScaleX, ScaleY, CenterX, CenterY
SkewTransform Warps your coordinate system by slanting it a number of degrees. For example, if you draw a square, it becomes a parallelogram. AngleX, AngleY, CenterX, CenterY
MatrixTransform Modifies your coordinate system using matrix multiplication with the matrix you supply. This is the most complex option -- it requires some mathematical skill. Matrix
TransformGroup Combines multiple transforms so they can all be applied at once. The order in which you apply transformations is important -- it affects the final result. For example, rotating a shape (with RotateTransform) and then moving it (with TranslateTransform) sends the shape off in a different direction than if you move it and then rotate it. N/A
Table 2: Transform Classes

Technically, all transforms use matrix math to alter the coordinates of your shape. However, using prebuilt transforms such as TranslateTransform, RotateTransform, ScaleTransform, and SkewTransform is far simpler than using the MatrixTransform and trying to work out the right matrix for the operation you want to perform. When you perform a series of transforms with TransformGroup, Silverlight fuses your transforms together into a single MatrixTransform, ensuring optimal performance.

Using a Transform

To transform an element, you set its RenderTransform property with the transform object you want to use. Depending on the transform object you're using, you'll need to fill in different properties to configure it, as detailed in Table 2.

For example, if you're rotating a shape, you need to use the RotateTransform and supply the angle in degrees. Here's an example that rotates a square clockwise by 25 degrees:

<Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow"
  Canvas.Left="100" Canvas.Top="100">
    <Rectangle.RenderTransform>
      <RotateTransform Angle="25" />
   </Rectangle.RenderTransform>
</Rectangle>

When you rotate a shape in this way, you rotate it about the shape's origin (the top-left corner). If you want to rotate a shape around a different point, you can use the handy RenderTransformOrigin property. This property sets the center point using a proportional coordinate system that stretches from 0 to 1 in both dimensions. In other words, the point (0, 0) is designated as the top-left corner, and (1, 1) is the bottom-right corner. (If the shape region isn't square, the coordinate system is stretched accordingly.)

With the help of the RenderTransformOrigin property, you can rotate any shape around its center point using markup like this:

<Rectangle Width="80" Height="10" Stroke="Blue" Fill="Yellow"
  Canvas.Left="100" Canvas.Top="100"    RenderTransformOrigin="0.5,0.5">
    <Rectangle.RenderTransform>
   <RotateTransform Angle="25" />
  </Rectangle.RenderTransform>
 </Rectangle>

Animating a Transform

To use a transform in animation, the first step is to define the transform. (An animation can change an existing transform but not create a new one.) For example, imagine you want to allow a rectangle to rotate. This requires RotateTransform:


<Rectangle x:Name="rect" Width="80" Height="50" Stroke="Blue" Fill="Yellow"
  Canvas.Left="100" Canvas.Top="100" RenderTransformOrigin="0.5,0.5">
    <Rectangle.RenderTransform>
      <RotateTransform></RotateTransform>
    </Rectangle.RenderTransform>
  </Rectangle>

Now here's a storyboard that makes the rectangle rotate when the mouse moves over it. It uses the target property (UIElement.RenderTransform).Angle -- in other words, it reads the RenderTransform property of the Rectangle and modifies the Angle property of the RotateTransform object that's defined there. The fact that the RenderTransform property can hold a variety of different transform objects, each with different properties, doesn't cause a problem. As long as you're using a transform that has an angle property, this trigger will work.

<Rectangle x:Name="rect" Width="80" Height="50" Stroke="Blue" Fill="Yellow"
Canvas.Left="100" Canvas.Top="100" RenderTransformOrigin="0.5,0.5"
MouseEnter="rect_Enter">
   <Rectangle.RenderTransform>
      <RotateTransform></RotateTransform>
         </Rectangle.RenderTransform>
     <Rectangle.Resources>
        <Storyboard x:Name="rotateStoryboard">
          <DoubleAnimation
          Storyboard.TargetName="rect"
          Storyboard.TargetProperty="(UIElement.RenderTransform).Angle"
          To="360" Duration="0:0:0.8" RepeatBehavior="Forever"></DoubleAnimation>
       </Storyboard>
    </Rectangle.Resources>
  </Rectangle>

Finally, an event handler starts the storyboard:

private void rect_Enter(object o, EventArgs e)
{
    rotateStoryboard.Begin();
}

The rectangle rotates one revolution every 0.8 seconds and continues rotating perpetually. While the rectangle is rotating, it's still completely usable -- for example, it still raises the MouseLeftButtonDown event if you click it.

To stop the rotation, you can use a second trigger that responds to the MouseLeave event. At this point, you could call the Storyboard.Stop() method, but this will cause the button to jump back to its original orientation in one step. A better approach is to start a second animation that replaces the first. Here's how the second animation is defined:

<Storyboard x:Name="revertStoryboard">
   <DoubleAnimation
   Storyboard.TargetName="rect"
   Storyboard.TargetProperty="(UIElement.RenderTransform).Angle"
   To="0" Duration="0:0:0.2"></DoubleAnimation>
</Storyboard>

This animation seamlessly rotates the rectangle back to its original orientation in a snappy 0.2 seconds. You can place this storyboard in the same Rectangle.Resources collection as the first animation.

All you need to do is attach an event handler to the Rectangle.MouseLeave event that runs the storyboard:

private void rect_Leave(object o, EventArgs e)
{
   revertStoryboard.Begin();
}


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 
Dr. Dobb's TV