Exploring the Microsoft Client Continuum

Color, Scale & Rotation

We should remember that one of the key differences between working with visual elements in Flash as opposed to working with visual elements in Silverlight is that Silverlight stores the visual definitions in XAML. When we start dealing with issues of Scale and Rotation, this difference becomes more apparent; certain properties are implicit in Flash whereas they need to be explicitly defined in the XAML for Silverlight. Scale and Rotation are two such properties. Let's see how this works.

Consider this simple Flash example:

Generated with this code:

Before we can do a similar procedure in Silverlight, we would need to explicitly define a RenderTransform on the visual element and name the properties on our control Tile like so:

We could have used LayoutRoot directly as the visual canvas, but we're going to add a couple more elements to this User Control later, so we left LayoutRoot visually empty and defined a Canvas child named bkg to be what we actually see. Notice the RenderTransformOrigin is a way to move the equivalent of the registration point for this Canvas as well.

The explicit definition of the scale and rotation transformations are found in Lines 10 through 15 above. Since we want to apply more than one transform, we need to wrap them up in a TransformGroup. The ScaleTransform on Line 12 is named scale and the RotateTransform is named rotation. Since we will be controlling them in code, their initial values are all set to have no discernable effect at the moment.

The code that adds the controls on Page.xaml looks very similar to our ActionScript logic, but with a couple key differences to note:

At Line 29, rotation is the name we gave the RotationTransform we defined in Tile, but we still need to be specific and set the Angle of this transform, since rotation is just the name we gave it and not the property itself. The same goes for the ScaleX and ScaleY values for our ScaleTransform we named scale on Line 30. Its also important to notice that full scale in ActionScript 2.0 has a value of 100, while full scale in Silverlight has a value of 1.0. So we are dealing with decimals from 0.0 to 1.0 here, not values from 0 to 100. Lines 31 through 34 give a preview of setting color in Silverlight by using a SolidColorBrush, but we will discuss this further next.

If we ran our Silverlight rebuild, it would look something like this right now:

But let's start turning this project into something a little more fun. I'm going to make the following changes to Page.xaml and Tile.xaml, adjusting their sizes a bit:

I changed the size of bkg in Tile.xaml and also added an Ellipse that would sit outside the influence of our RenderTransforms. The RenderTransforms apply to the Canvas they are under. In this case, the Canvas is our visual element bkg and not the local root of this control, LayoutRoot.

Let's beef up the code behind file Tile.xaml.cs to have it accept a rotation target value and a Storyboard object to animate it procedurally. After the same X and Y definitions we've been using in every project, the rest of the code for Tile.xaml.cs looks like this:

On Page.xaml.cs, we want to fill out the UserControl_Loaded() handler we call from Page.xaml and also create a Storyboard object that will constantly update the targetAngle and scale values for each Tile. All of the code except the actual Storyboard animation logic looks like this:

Line 28 is the code that is setting the background color of each bkg canvas in Tile.xaml. We've already seen a few XAML brushes in previous lessons. But if you want to manipulate an object's fill or background with a solid color in code, you use a SolidColorBrush. If you want fine control over the color directly, you can then use the Color.FromArgb() function to set the color to anything you like. Whereas Flash typically breaks down a color into its three byte components (red, green, and blue), Silverlight exposes a fourth byte for the alpha, a. Therefore, Color.FromArgb() expects fourparameters; alpha, red, green, and blue.  These parameters must explicitly be of type byte. That's why I need to cast them as such with "(byte)" before calculating the values. If you follow the logic above in Line 28 through Line 31, you'll see how the X and Y properties of each Tile are tweaking the green and blue byte values, giving us a full table of color samples.

Also notice what we're doing in Line 35 and Lines 42 through Line 47. Since Silverlight doesn't provide an _xmouse and _ymouse property by default for us to use in our animation logic, we need to duplicate this functionality by having a local Point object updated whenever the mouseMoved() is called. With this defined, we can now query this mouse object from anywhere to find out the current location of the cursor relative to Page.xaml. We will use this in the main Storyboard's animation loop like this:

Using a little math magic, we determine the distance of each Tile from the cursor and use this to set each ScaleX and ScaleY value directly (Lines 53 - 55, 58 and 59). We can also use some more trigonometry to determine the angle from each Tile's origin to the current location of the mouse and have it rotate to point to it. If the distance is less than 200 pixels, the Tiles will flicker and spin to point to the mouse. As the mouse moves farther away, the Tiles that are no longer in the effected area flicker and loop back.

Here is the Silverlight result:

A Variation on the Theme

There is another transform I should probably mention, TranslateTransform. All the lessons we have created so far have us directly setting the X and Y properties of our User Controls in a Canvas, so a need to move (or translate) them with a RenderTransform has come up. But here is a simple variation of the above example that can give us a substantially different experience. Instead of using a dynamic solid color for each Tile's bkg, we want to use a picture pic3.png we have added to our solution as an ImageBrush, painting each Tile according to it's X and Y location. This means we will need to shift the ImageBrush position for each Tile dynamically as well, and here is where a TranslateTransform can come in handy.

Here is how we changed Tile.xaml to make this happen:

The actual ScaleTransform and RotateTransform or even code behind Tile.xaml.cs haven't changed, but now bkg has an ImageBrush defined as its Fill, which can be offset by using a TranslateTransform.

Here are the changes in Page.xaml.cs that take advantage of this:

We tweak the ImageBrush to move in the opposite direction of where we place the Tile, so that its position on the Canvas and the appropriate section of the Source image line up.

Most importantly, though, I also add a strategic PNG Image with a transparent region in the middle over the whole Tiles collection to visually constrain the area I want to focus on while decorate the background as well.

This top Image helps sell the whole effect with some subtle shadow work and edges, all done in Photoshop. It adds depth and realism to the experience and makes the whole thing seem a bit richer.

Here is the finished Silverlight variation:

While this lesson was on Color, Scale and Rotation, the key line of code used the trigonometry function Math.Atan2() to get us the target angle values we wanted. In our next lesson, we'll explore this and other trigonometry functions more closely.

Additional Resources

There are several great Flash developers that have done much over the years to make Math and Trigonometry more accessible to interactive designers. Here are few books and blogs by some of my favorites:

Have a question or comment on this article? Have a suggestion for new content?
Send your feedback.
Microsoft Communities