Animations

This control and resource stuff is great, but it’s not exactly exciting, we know. We promised you animations, and animations you shall have. The best way to make animations in WPF is with a tool called Expression Blend (available at http://www.microsoft.com/expression), but in this case, we’ll show you how to do it the hard way so that you’ll know what’s going on in the XAML. In this example, you’re going to start with a simple square, and perform some of the more basic animations on it. The square is in fact an instance of the built-in Rectangle control, which is part of the WPF schema. However, you can apply these animations to many other controls.

The first thing to do is define the Rectangle control. Create a new WPF project to start with. You could drag a Rectangle control out of the toolbar onto the window, but in this case, it’s easier to just define the rectangle in the XAML. Add the following element inside the <Grid> element:

<Rectangle Name="myRectangle" Width="100" Height="100">
</Rectangle>

Now you should see a square in the Design window, 100 units on a side. You didn’t define the Margin property, so the square will be centered in the window, which is fine. The first thing you’re going to do is animate the color of the square, and to do that, you’ll need the square to have some color first. If you click on the Rectangle element, you’ll see it has a Fill property, which is the interior color of the square (as opposed to the outside border, which we’ll leave blank). You could simply set the Fill property to a color, but you can’t manipulate the Fill property directly from an event, which is what you’ll want to do later. That means you have to define a Brush, which is a property of Fill that you use for applying color, and other drawing properties. Inside the Rectangle element, add this new subelement:

<Rectangle.Fill>
    <SolidColorBrush x:Name="rectangleBrush" Color="Blue" />
</Rectangle.Fill>

What you’ve done here is define a Brush, specifically a SolidColorBrush—there are more complicated Brush types, used for gradients and other fancy drawing tools, but we’ll stick with a solid color here. Notice specifically that you’ve used the x element to give this brush a name that can be referred to elsewhere in the code—that’s critical to the animation, as you’ll see in a moment.

Triggers and Storyboards

So far, you haven’t animated anything. To start the animation, you’ll need a trigger. Triggers are attached to WPF elements, and they’re similar to event handlers in that they react to events within the application, but they don’t necessarily require you to write any code. This trigger will be attached to the Rectangle element, so below your new <Rectangle.Fill> element, add another element, <Rectangle.Triggers>:

<Rectangle.Fill>
    <SolidColorBrush x:Name="rectangleBrush" Color="Blue" />
</Rectangle.Fill>
<Rectangle.Triggers></Rectangle.Triggers>

Notice that IntelliSense provides the closing tag for you. This subelement will hold any triggers you define for Rectangle, and you’ll add one in a moment.

Much like event handlers, triggers need events to react to. WPF defines two different kinds of events, routed events and attached events. Routed events are events raised normally by a single control; attached events are more complicated, so we won’t worry about them here. You’re going to use a routed event for this trigger, the Loaded event on the Rectangle element. As the name implies, this event is fired when the Rectangle element is loaded, which happens as soon as the application starts. Add that trigger element now, and then we’ll define the animation to go inside it:

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

    </EventTrigger>
</Rectangle.Triggers>

Animations live inside special elements called storyboards, so that’s what you need to define next. The trigger element can’t contain just a storyboard by itself; it has to contain a storyboard action. Therefore, you first need to add a <BeginStoryboard> element inside the EventTrigger element. Inside the BeginStoryboard element, you define the Storyboard:

<Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.Loaded">
        <BeginStoryboard>
            <Storyboard>

            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</Rectangle.Triggers>

You can also define a storyboard elsewhere in your code, as a resource. You’ll see how that works in the next example, but we won’t do that here.

After all these nested elements, it’s finally time to get to the animation. WPF defines several different kinds of animations, depending on what you’re animating. You can think of an animation as changing a property of an element over time. For example, if you define an animation to make a rectangle increase in width, you’re changing its Width property, which is defined as a double data type, so you’d use the DoubleAnimation for the animation type. In this case, you’re going to change the color of the square, so you’ll use the ColorAnimation type. Add the following code inside the Storyboard element:

<EventTrigger RoutedEvent="Rectangle.Loaded">
    <BeginStoryboard>
        <Storyboard>
            <ColorAnimation
                Storyboard.TargetName="rectangleBrush"
                Storyboard.TargetProperty="Color"
                From="Blue" To="Red" Duration="0:0:10"
                AutoReverse="True" RepeatBehavior="Forever" />
        </Storyboard>
    </BeginStoryboard>
</EventTrigger>

This all breaks down pretty easily. First, you open the <ColorAnimation> tag. Then you define the TargetName of the storyboard; that’s the rectangleBrush you defined earlier, and now you know why you gave it a name, so you could refer to it down here. You also have a TargetProperty to indicate what property of the target Brush you’re going to change, which in this case is Color. So far, so good.

The next few elements define how the animation works. The From property indicates the starting value of the animation; in this case, the starting color. The To property indicates the value where you want to end up; in this case, Red. The Duration indicates how long it takes for the value to change from the starting value to the final value. The duration is measured in hours, minutes, and seconds, so 0:0:10 means the color change will take 10 seconds to happen. The last line just adds a bit of class to the animation: the AutoReverse property indicates that the animation will turn the square blue, then back to red, automatically. The RepeatBehavior is used to limit how many times the animation will repeat; the value of Forever means that it’ll repeat until the user closes the application.

Run your application now. You’ll see your square, centered in the window, slowly changing from blue through purple to red, and back again, every 10 seconds. Feel free to stop the application and play with the values to get different effects.

Tip

If you wanted to shift colors between more than two values—say, down the spectrum from red to yellow to green to blue—you’d use a different type of animation called ColorAnimationUsingKeyFrames. That’s a little complex for this example, though.

The result looks like Figure 19-5, and the full XAML is shown in Example 19-4.

You can’t tell this on the page, but this square is slowly changing color.

Figure 19-5. You can’t tell this on the page, but this square is slowly changing color.

Example 19-4. You can create animation effects entirely in XAML, without having to write any C# code

<Window x:Class="Example_19_4_ _ _ _Animations.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <Rectangle Name="myRectangle" Width="100" Height="100">
            <Rectangle.Fill>
                <SolidColorBrush x:Name="rectangleBrush" 
                                 Color="Blue" />
            </Rectangle.Fill>
            <Rectangle.Triggers>
                <EventTrigger RoutedEvent="Rectangle.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation 
                                Storyboard.TargetName=
                                   "rectangleBrush"
                                Storyboard.TargetProperty="Color"
                                From="Blue" To="Red" 
                                Duration="0:0:10"
                                AutoReverse="True" 
                                RepeatBehavior="Forever" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Rectangle.Triggers>
        </Rectangle>
    </Grid>
</Window>

It’s important to note here that you haven’t written a single line of C# code for this example. This entire animation happened declaratively, in the XAML file. WPF contains the code to automate all of this for you.

Animations As Resources

We mentioned earlier that you can define an animation as a resource; in this next example, we’ll show you how. You’ll rotate the square in the window, and you’ll see how it can respond to user events.

Rotating elements in WPF is pretty easy. You’ll need to add a RenderTransform property to the Rectangle, just like you added the Fill element to hold the Brush. Add the following element after the Rectangle.Fill element from earlier:

<Rectangle.RenderTransform>
    <RotateTransform x:Name="rectangleRotate" Angle="0.0" />
</Rectangle.RenderTransform>

You’ve defined a RenderTransform element, with two properties. As with the Brush, you’ve given the RotateTransform a name, so you can refer to it from elsewhere in your code. You’ve also given it a starting angle, in this case, 0.

If you’re going to rotate an element, you need to define the point on which the rotation will center; the hinge, if you want to imagine it that way. The default for a Rectangle is the upper-left corner, but we’d rather use the center point of the square instead. So, go back up to the definition of the Rectangle element, and add the following property:

<Rectangle Name="myRectangle" Width="100" Height="100"
           RenderTransformOrigin="0.5,0.5">

The RenderTransformOrigin property is a nice shortcut for defining rotation points. Instead of requiring you to count pixels from the edge of the element, or the window, you can provide two coordinates between 0 and 1 that define the point in relation to the edges of the element. In this case, 0.5,0.5 indicates halfway through each dimension, or the exact center of the square.

Now that you have the necessary properties set on the rectangle, you can define the animation in a storyboard. This time, you’ll define the storyboard as a resource for the window itself so that other elements in the window can use this rotate animation. Go up to the Window definition, and define a subelement, <Window.Resources>, before the <Grid> element, like this:

<Window x:Class="Example_19_5_ _ _ _More_animation.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>

    </Window.Resources>
    <Grid>

Within the Resources element, you’ll define the storyboard. You don’t need the <BeginStoryboard> element this time, because you’re not defining an action, you’re just defining the storyboard itself. Add the following code for the storyboard:

<Window.Resources>
    <Storyboard x:Key="Rotate">
        <DoubleAnimation
            Storyboard.TargetName="rectangleRotate"
            Storyboard.TargetProperty="Angle"
            From="0.0" To="360.0" Duration="0:0:10"
            RepeatBehavior="Forever"/>
    </Storyboard>
</Window.Resources>

Notice first that you’re providing the storyboard itself with a name that can be referenced elsewhere in the code; that’s necessary because this is a resource for the entire window.

As before, the storyboard contains an animation. This time, you’re changing the angle of the Rectangle, which is expressed as a double, so you’re using a DoubleAnimation. You provide the TargetName and TargetProperty, just as you did in the previous example, but this time you’re targeting the RotateTransform property instead of the Brush. The From and To elements go from zero to 360, or a full rotation, and the Duration indicates that it’ll take 10 seconds to accomplish. The RepeatBehavior property indicates that the square will keep rotating until something stops it.

Now you’ve defined the animation, but it’s not associated with any triggers. Instead of having the animation start when the Rectangle loads, you’ll have it start when the user moves the mouse over the square. To do that, you’ll need a new EventTrigger element, associated with a different event. Add the following code inside the <Rectangle.Triggers> element, but after the closing tag of the trigger that’s already there:

<EventTrigger RoutedEvent="Rectangle.MouseEnter">
    <BeginStoryboard Storyboard="{StaticResource Rotate}"
                     x:Name="BeginRotateStoryboard"/>
</EventTrigger>

The RoutedEvent that you’re using this time is called MouseEnter, and it’s raised by the Rectangle itself. Within the trigger is the BeginStoryboard element that you saw in the previous example, but instead of defining the storyboard here, you have a reference to the resource you defined earlier for the Window. You’ve also given the BeginStoryboard a name, so you can refer to that later; you’ll see why in a minute.

For now, run the application, move the mouse over the square, and you’ll see that the square rotates as it continues to change colors, as you’d see in Figure 19-6 if this book weren’t black-and-white and static. You can experiment with the values in the storyboard, and with the angle and rotation origin defined in the Rectangle as well.

You still can’t see it, but now the square is rotating in addition to changing color.

Figure 19-6. You still can’t see it, but now the square is rotating in addition to changing color.

Let’s take this animation one step further, and have the animation pause when the user moves the mouse off the square. To do that, you simply need to add another EventTrigger, after the one you just added, to handle a different event:

<EventTrigger RoutedEvent="Rectangle.MouseLeave">
    <PauseStoryboard BeginStoryboardName="BeginRotateStoryboard" />
</EventTrigger>

Here, you’re handling the MouseLeave event, which is raised when the cursor exits the element. Instead of the BeginStoryboard, you’re using a PauseStoryboard action here, which halts the execution of the BeginStoryboard in the previous trigger—that’s why you gave it a name, so you could refer to it here.

Run your application again, and you’ll see that the animation stops when the mouse leaves the square. If you bring the mouse back inside the square the animation starts again, but the angle starts over from zero. Fixing that would be somewhat more complicated, and beyond the scope of this chapter. Once again, notice that you still haven’t written any C# code to accomplish these animations, even with the event triggers. The full XAML file for this example is shown in Example 19-5.

Example 19-5. This time you’re creating the animation as a resource at the window level, but you still don’t need to write any C# code

<Window x:Class="Example_19_5_ _ _ _More_animation.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <Storyboard x:Key="Rotate">
            <DoubleAnimation
                Storyboard.TargetName="rectangleRotate"
                Storyboard.TargetProperty="Angle"
                From="0.0" To="360.0" Duration="0:0:10"
                RepeatBehavior="Forever"/>
        </Storyboard>
    </Window.Resources>
    <Grid>
        <Rectangle Name="myRectangle" Width="100" Height="100" 
                   RenderTransformOrigin="0.5,0.5">
            <Rectangle.Fill>
                <SolidColorBrush x:Name="rectangleBrush" 
                                 Color="Blue" />
            </Rectangle.Fill>
            <Rectangle.RenderTransform>
                <RotateTransform x:Name="rectangleRotate" 
                                 Angle="0.0" />
            </Rectangle.RenderTransform>
            <Rectangle.Triggers>
                <EventTrigger RoutedEvent="Rectangle.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation 
                                Storyboard.TargetName=
                                             "rectangleBrush"
                                Storyboard.TargetProperty="Color"
                                From="Blue" To="Red" 
                                Duration="0:0:10"
                                AutoReverse="True" 
                                RepeatBehavior="Forever" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
                <EventTrigger RoutedEvent="Rectangle.MouseEnter">
                    <BeginStoryboard 
                           Storyboard="{StaticResource Rotate}"
                           x:Name="BeginRotateStoryboard"/>
                </EventTrigger>
                <EventTrigger RoutedEvent="Rectangle.MouseLeave">
                    <PauseStoryboard 
                       BeginStoryboardName="BeginRotateStoryboard" />
                </EventTrigger>
            </Rectangle.Triggers>
        </Rectangle>
    </Grid>
</Window>
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset