This example shows how to use a WPF storyboard to animate a rectangle moving along a path. You can do this all in XAML code, although it’s pretty complicated.
The main window contains a Canvas that contains the red path and the moving rectangle. The following code shows how the program defines the red path.
<Path Stroke="Red" StrokeThickness="3"> <Path.Data> <PathGeometry Figures= "M 50,110 C 50,20 150,20 150,110 150,250 250,250 250,160 250,60 50,210 50,110"/> </Path.Data> </Path>
The path is drawn as a series of connected splines defined by the WPF drawing mini-language. The M command makes the curve move to the coordinates that follow (50, 110).
The C command begins a spline. (The C stands for “curve.”) The curve starts at the current location and ends at the third location that follows, in this case (150, 110). The two points in between are control points that determine the curve’s direction at the two end points. The curve leaves the initial point heading toward the first control point. It then arrives at the final point coming from the direction of the second control point.
The picture on the right shows the form with just the first spline drawn. The blue circles are the curve’s end points. The green circles are the control points. The dashed lines show how the control points determine the direction of the curve at its end points.
The following code shows the beginning of the rectangle’s definition.
<Rectangle Width="50" Height="30" Fill="LightBlue" Stroke="Blue"> <!-- We animate the following transformation to move the rectangle. Initially it's just an identity transformation. --> <Rectangle.RenderTransform> <TransformGroup> <TranslateTransform X="-25" Y="-30"/> <MatrixTransform x:Name="rectangleTransform"> <MatrixTransform.Matrix > <Matrix /> </MatrixTransform.Matrix> </MatrixTransform> </TransformGroup> </Rectangle.RenderTransform>
The Rectangle contains a RenderTransform that transforms the Rectangle before it is drawn. The RenderTransform property can only contain a single transformation object. In this case that object is a TransformGroup containing two transformations.
The first is a translation by half the rectangle’s width in the -X direction and by the rectangle’s height in the -Y direction. Normally the Rectangle object is drawn with its lower left corner at the origin. This translation moves it so it’s lower middle point lies at the origin.
The second transformation is simply a MatrixTransform named rectangleTransform. Initially it just contains an identity transformation so it doesn’t change the Rectangle. The reason is it here is that the program will modify it (using its name) during the animation.
The following code shows the rest of the Rectangle‘s definition.
<!-- The Rectangle.Loaded event makes the storyboard start. --> <Rectangle.Triggers> <EventTrigger RoutedEvent="Rectangle.Loaded"> <BeginStoryboard> <Storyboard> <MatrixAnimationUsingPath Storyboard.TargetName="rectangleTransform" Storyboard.TargetProperty="Matrix" DoesRotateWithTangent="True" Duration="00:00:10" RepeatBehavior="Forever" > <MatrixAnimationUsingPath.PathGeometry> <PathGeometry Figures= "M 50,110 C 50,20 150,20 150,110 150,250 250,250 250,160 250,60 50,210 50,110"/> </MatrixAnimationUsingPath.PathGeometry> </MatrixAnimationUsingPath> </Storyboard> </BeginStoryboard> </EventTrigger> </Rectangle.Triggers> </Rectangle>
The next part of the Rectangle‘s definition is it Triggers section. This section defines actions that should occur when properties change or certain actions occur. In this example, the section contains an EventTrigger that executes when the Rectangle.Loaded event occurs. In other words, it executes when the Rectangle is loaded.
When that event occurs, the trigger starts a BeginStoryboard action. The BeginStoryboard object starts the Storyboard that it contains.
The Storyboard executes the MatriAnimationUsingPath that it contains. That object modifes the rectangleTransform object defined earlier, which is the second of the Rectangle‘s transformations. It updates that object’s Matrix, which is initially an identity matrix.
The setting DoesRotateWithTangent="True" property makes the rectangle rotate to remain parallel to the curve as it moves along the curve. The Duration property makes the animation take 10 seconds, and the RepeatBehavior="Forever" makes the animation repeat itself after it finishes so the Rectangle keeps making laps around the curve.
Finally the code sets the MatriAnimationUsingPath object’s PathGeometry property equal to the same curve drawn earlier in the code.
When the program starts, the Rectangle loads. That fires the trigger, which starts the animation. The animation modifies the rectangleTransform matrix so it follows the path and rotates the Rectangle so it remains parallel to the path.