I answered a post on the Silverlight forums recently about creating reusable animations for an Image, and thought that it was worth a blog entry to expand on it a little.
I am looking here at two common approaches to creating reusable animations within a single project:
-
Create the animation in xaml (using Blend) on one element and then change the target in code. This is easier to do but means you can only play one animation at a time (because only one animation actually exists)
-
Create the animation purely in code. This means you can create as many as you want and have them all playing at the same time, and writing the code gives you more control over changing the animation conditionally at run time.
Of course you can also have a combination of the two (so you could create the animation in blend, then create a copy of it in code and manipulate it)
Using the Xaml Approach
Here's an example of the first approach. This is the Xaml created by recording an animation in Blend against "Image1". Notice that I have given the two DoubleAnimationUsingKeyFrames elements names (GrowImageScaleXAnimation and GrowImageScaleYAnimation) so that it is easy to change their properties in code later on:
<Storyboard x:Name="GrowImage" AutoReverse="True">
<DoubleAnimationUsingKeyFrames
x:Name="GrowImageScaleXAnimation"
BeginTime="00:00:00"
Storyboard.TargetName="Image1"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<SplineDoubleKeyFrame
KeyTime="00:00:00.5000000"
Value="1.1"
KeySpline="0.24,0.75,0.9,1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
x:Name="GrowImageScaleYAnimation"
BeginTime="00:00:00"
Storyboard.TargetName="Image1"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame
KeyTime="00:00:00.5000000"
Value="1.1"
KeySpline="0.24,0.75,0.9,1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
So if you have two images like this:
<Image x:Name="Image1" Width="100" Height="100" Source="Images/beta.jpg"
MouseLeftButtonUp="Image_MouseLeftButtonUp" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
<Image x:Name="Image2" Width="100" Height="100" Source="Images/beta.jpg"
MouseLeftButtonUp="Image_MouseLeftButtonUp" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
You can write the following code to play the animation on either one:
private void PlayXamlImageAnimation(string ImageName)
{
GrowImage.Stop();
Storyboard.SetTargetName(GrowImageScaleXAnimation, ImageName);
Storyboard.SetTargetName(GrowImageScaleYAnimation, ImageName);
GrowImage.Begin();
}
Using the Pure Code Approach
For the pure code approach you create the animation in code and attach it to the image. Here is my code to create the animation:
private Storyboard CreateAnimation(DependencyObject image)
{
Storyboard board = new Storyboard();
board.AutoReverse = true;
DoubleAnimationUsingKeyFrames scaleXAnim =
GetAnimation(image, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)");
DoubleAnimationUsingKeyFrames scaleYAnim =
GetAnimation(image, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)");
board.Children.Add(scaleXAnim);
board.Children.Add(scaleYAnim);
return board;
}
private DoubleAnimationUsingKeyFrames GetAnimation(DependencyObject image,string propertyPath)
{
DoubleAnimationUsingKeyFrames animation = new DoubleAnimationUsingKeyFrames();
animation.BeginTime = TimeSpan.FromSeconds(0);
Storyboard.SetTarget(animation, image);
Storyboard.SetTargetProperty(animation, new PropertyPath(propertyPath, new object[0]));
SplineDoubleKeyFrame spline = new SplineDoubleKeyFrame();
spline.KeyTime = TimeSpan.FromSeconds(0.5);
spline.Value = 1.1;
KeySpline keySpline = new KeySpline();
keySpline.ControlPoint1 = new Point(0.24, 0.75);
keySpline.ControlPoint2 = new Point(0.9, 1);
spline.KeySpline = keySpline;
animation.KeyFrames.Add(spline);
return animation;
}
This produces exactly the same animation that was shown in the Xaml above, but is quite a bit more work (in truth I still find it easier to record this in Blend, then manually convert it to code from the Xaml) The benefit is that we have more control and we can get as many animation instances we want so that we can have them all playing at the same time on different images. So in this example I create two Storyboards and then instantiate them against my images in the constructor for the page:
Storyboard image1Animation;
Storyboard image2Animation;
public Page()
{
InitializeComponent();
image1Animation = CreateAnimation(Image1);
image2Animation = CreateAnimation(Image2);
}
Then it is simple a matter of playing the animations when needed.
You can download the source from my sky drive:
Cheers
Ian