Silverlight applications can be dynamic even if they do not use
JavaScript. The content can be transformed and animated, both which we will
cover in this chapter. The transformation is nothing that you can watch, but
rather a calculation that takes effect when the plug-in renders the
Silverlight content. For example, you can rotate or skew elements. An
animation, on the other hand, can really change the visual appearance of the
applications: elements may move or change their color. As always, you will
find many small and self-contained examples that showcase the most
interesting and important Silverlight
options.
Transformations
A transformation is technically only a change of one or more values.
For instance, if an element is rotated, its position and the location of
all the drawing points of the element change. If an element is moved to
another position (that's a transformation as well), basically the
positions of all corners of the element change (if we leave fillings
aside). Silverlight supports five transformations:
-
TranslateTransform
-
Changes the position of an element
- ScaleTransform
-
Scales an element by multiplying its dimension horizontally and
vertically
- SkewTransform
-
Skews an element by using a horizontal and a vertical angle
- RotateTransform
-
Rotates an element by using an angle
- MatrixTransform
-
Multiplies all points of an element by a given matrix, and uses the result
as the new value
Let's start with the
element, which just changes the position of an element, much like
setting a related property such as Canvas.Left or
Canvas.Top would do.
To execute a transformation, you have to use the
<Element.RenderTransform>
element. You need to replace Element with the
type of object you want to transform. So, to transform a
object, use
. To transform a
object, use .
Within the
<Element.RenderTransform>
element, you need to put the transformation element; in this example, it
is
<TranslateTransform>. This element expects two
attributes,
X and
Y, denoting the new
x and
y coordinates of the
associated element's left corner, as you can see here:
<TextBlock Text="...">
<TextBlock.RenderTransform>
<TranslateTransform X="10" Y="20" />
</TextBlock.RenderTransform>
</TextBlock>
Example 1 starts with the "Hello World" example and translates both a rectangle and a text
block. In the result, you will see both the original elements and the
translated ones (Figure 1).
Example 7-1. Translating elements, the XAML file (Page.xaml, project
TranslateTransform)
<UserControl x:Class="TranslateTransform.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="450" Height="300"> <Grid x:Name="LayoutRoot" Background="White"> <Canvas>
<Rectangle Width="300" Height="150" Stroke="Orange" StrokeThickness="15" /> <TextBlock FontFamily="Arial" FontSize="56" Canvas.Left="25" Canvas.Top="40" Foreground="Black" Text="Silverlight" />
<Rectangle Width="300" Height="150" Stroke="Orange" StrokeThickness="15"> <Rectangle.RenderTransform> <TranslateTransform X="350" Y="175" /> </Rectangle.RenderTransform> </Rectangle>
<TextBlock FontFamily="Arial" FontSize="56" Canvas.Left="25" Canvas.Top="40" Foreground="Black" Text="Silverlight"> <TextBlock.RenderTransform> <TranslateTransform X="350" Y="175" /> </TextBlock.RenderTransform> </TextBlock>
</Canvas> </Grid> </UserControl>
|
You can scale elements using .
You can scale both horizontally (ScaleX
attribute) and vertically (ScaleY attribute), and may also
provide the center coordinates (CenterX and CenterY
attributes). The scaling value is actually a factor. For instance, a
scaling value of 2 doubles the horizontal or vertical size,
whereas a factor of 0.5 halves it. Example 2 scales both ways, as Figure 2
shows.
Example 7-2. Scaling elements, the XAML file (Page.xaml, project ScaleTransform)
<UserControl x:Class="ScaleTransform.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="600" Height="400"> <Grid x:Name="LayoutRoot" Background="White"> <Canvas>
<Rectangle Width="300" Height="150" Stroke="Orange" StrokeThickness="15" /> <TextBlock FontFamily="Arial" FontSize="56" Canvas.Left="25" Canvas.Top="40" Foreground="Black" Text="Silverlight" /> <Rectangle Canvas.Left="350" Canvas.Top="175" Width="300" Height="150" Stroke="Orange" StrokeThickness="15"> <Rectangle.RenderTransform> <ScaleTransform ScaleX="1.5" ScaleY="0.5" /> </Rectangle.RenderTransform> </Rectangle> <TextBlock FontFamily="Arial" FontSize="56" Canvas.Left="375" Canvas.Top="215" Foreground="Black" Text="Silverlight"> <TextBlock.RenderTransform> <ScaleTransform ScaleX="1.5" ScaleY="0.5" /> </TextBlock.RenderTransform> </TextBlock>
</Canvas> </Grid> </UserControl>
|
The next transformation effect on our list is skewing, represented
in Silverlight using the element. You can skew
using a horizontal angle (AngleX) and a vertical angle
(AngleY). Again, you can provide the center of the
transformation by setting the CenterX and
CenterY attributes. The code in Example 3
uses a horizontal skewing of 45 degrees and a vertical skewing of -30
degrees (which is the same as 330 degrees, because 360 degrees is a full
circle). Figure 3 shows the result.
Example 3. Skewing elements, the XAML file (Page.xaml, project SkewTransform)
<UserControl x:Class="SkewTransform.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="600" Height="400"> <Grid x:Name="LayoutRoot" Background="White"> <Canvas>
<Rectangle Width="300" Height="150" Stroke="Orange" StrokeThickness="15" /> <TextBlock FontFamily="Arial" FontSize="56" Canvas.Left="25" Canvas.Top="40" Foreground="Black" Text="Silverlight" />
<Rectangle Canvas.Left="350" Canvas.Top="175" Width="300" Height="150" Stroke="Orange" StrokeThickness="15"> <Rectangle.RenderTransform> <SkewTransform CenterX="50" CenterY="25" AngleX="45" AngleY="-30" /> </Rectangle.RenderTransform> </Rectangle> <TextBlock FontFamily="Arial" FontSize="56" Canvas.Left="375" Canvas.Top="215" Foreground="Black" Text="Silverlight"> <TextBlock.RenderTransform> <SkewTransform CenterX="50" CenterY="25" AngleX="45" AngleY="-30" /> </TextBlock.RenderTransform> </TextBlock>
</Canvas> </Grid> </UserControl>
|
The final "simple" transformation is rotation, or
in Silverlight. All you need to
provide is the rotation angle (in degrees) in the Angle
property. By default, the element rotates around its top-left corner, that
is, the relative coordinates (0,0). You can define this rotation point
yourself by using the CenterX and CenterY
attributes.
In Example 4, the
element is rotated 45 degrees, around the point (150,50). To
appropriately rotate the element by the same number of degrees, you need to take into
account that the text block is translated 25 pixels to the right and 40
pixels to the bottom compared to the rectangle. This needs to be
compensated in the rotation point, so we get (150-25,50-r0), or (125,10).
As Figure 4 shows, the relative position of the text
block within the rectangle remains intact this way.
Example 4. Rotating elements, the XAML file (Page.xaml, project RotateTransform)
<UserControl x:Class="RotateTransform.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="600" Height="400"> <Grid x:Name="LayoutRoot" Background="White"> <Canvas>
<Rectangle Width="300" Height="150" Stroke="Orange" StrokeThickness="15" /> <TextBlock FontFamily="Arial" FontSize="56" Canvas.Left="25" Canvas.Top="40" Foreground="Black" Text="Silverlight" />
<Rectangle Canvas.Left="350" Canvas.Top="175" Width="300" Height="150" Stroke="Orange" StrokeThickness="15"> <Rectangle.RenderTransform> <RotateTransform Angle="-45" CenterX="150" CenterY="50" /> </Rectangle.RenderTransform> </Rectangle> <TextBlock FontFamily="Arial" FontSize="56" Canvas.Left="375" Canvas.Top="215" Foreground="Black" Text="Silverlight"> <TextBlock.RenderTransform> <RotateTransform Angle="-45" CenterX="125" CenterY="10" /> </TextBlock.RenderTransform> </TextBlock>
</Canvas> </Grid> </UserControl>
|
To use more transformations at one time, you have to group them (the
Silverlight object model and the XAML syntax do not allow multiple
transform elements directly underneath
<Element.RenderTransform>).
But this limitation does not lead to an enormous extra effort. All you
have to do is put a element within the
<Element.RenderTransform>
element and put your transformations in there. Example 5
shows such a transformation. As you can see in Figure 5, the code just translates the elements and skews
them (you will notice that in contrast to previous examples, there are no
Canvas.Left and Canvas.Top properties set for
the transformed objects).
Example 5. Grouping transformations, the XAML file (Page.xaml, project TransformGroup)
<UserControl x:Class="TransformGroup.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="600" Height="400"> <Grid x:Name="LayoutRoot" Background="White"> <Canvas>
<Rectangle Width="300" Height="150" Stroke="Orange" StrokeThickness="15" /> <TextBlock FontFamily="Arial" FontSize="56" Canvas.Left="25" Canvas.Top="40" Foreground="Black" Text="Silverlight" />
<Rectangle Width="300" Height="150" Stroke="Orange" StrokeThickness="15"> <Rectangle.RenderTransform> <TransformGroup> <TranslateTransform X="350" Y="175" /> <SkewTransform CenterX="425" CenterY="265" AngleX="45" AngleY="-30" /> </TransformGroup> </Rectangle.RenderTransform> </Rectangle> <TextBlock FontFamily="Arial" FontSize="56" Foreground="Black" Text="Silverlight"> <TextBlock.RenderTransform> <TransformGroup> <TranslateTransform X="375" Y="215" /> <SkewTransform CenterX="425" CenterY="265" AngleX="45" AngleY="-30" /> </TransformGroup> </TextBlock.RenderTransform> </TextBlock>
</Canvas> </Grid> </UserControl>
|
The complex calculations that are the basis for all Silverlight
transformations can be further generalized. Every point
(x,y) is multiplied by a 3x3
matrix to calculate its new coordinates. Since Silverlight supports only
2D, the third column of this matrix is always (0,0,1), because we cannot
use a z coordinate. However, the other two columns
are used by the previously shown transformations. For instance, the first
two values in the first two rows are used to scale and skew elements; the
first two values in the third row of the matrix provide the value to which
an element is translated. By setting all values at once, you can combine
translating, skewing, and scaling transformations.
The math behind these calculations is beyond the scope of this book,
but we will show you how this is done in markup. You need to use
the element; its
Matrix property expects the first two values of each of the
three matrix rows to be a comma-separated list. Have a look at the code in
Example 6 and then try to figure out what effect these
values will have. The solution is shown in Figure 6.
Example 6. Transforming using a matrix, the XAML file (Page.xaml, project MatrixTransform)
<UserControl x:Class="HelloWorld.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="600" Height="400"> <Grid x:Name="LayoutRoot" Background="White"> <Canvas>
<Rectangle Width="300" Height="150" Stroke="Orange" StrokeThickness="15" /> <TextBlock FontFamily="Arial" FontSize="56" Canvas.Left="25" Canvas.Top="40" Foreground="Black" Text="Silverlight" />
<Rectangle Canvas.Left="300" Width="300" Height="150" Stroke="Orange" StrokeThickness="15"> <Rectangle.RenderTransform> <MatrixTransform Matrix="1,1.5,1.25,1.25,1.5,1" /> </Rectangle.RenderTransform> </Rectangle> <TextBlock FontFamily="Arial" FontSize="56" Canvas.Left="325" Foreground="Black" Text="Silverlight"> <TextBlock.RenderTransform> <MatrixTransform Matrix="1,1.5,1.25,1.25,1.5,1" /> </TextBlock.RenderTransform> </TextBlock>
</Canvas> </Grid> </UserControl>
|
UI elements aren't the only things that you can
transform. Brushes support transformations by using
<NameOfBrush.Transform> and <NameOfBrush.RelativeTransform>
subelements (the latter element transforms using relative values). Also,
geometry elements (used for shapes) support a
<NameOfGeometry.Transform>
subelement and can have transformations applied to them .
|