Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Creating and Reusing Dynamic Animations in Silverlight

0.00/5 (No votes)
5 Sep 2008 1  
Creating dynamic animations, and a simple way to reuse them to reduce the XAML code size.

AgDynAnimationsSrc

Introduction

In this brief article, we are going to take a look at Silverlight animations, and will try to find a simple way to reuse the same animations for different elements. Creating animations in XAML code is easy, but it’s not that easy to reuse the same animation for different target objects.

In the worst case, you would have to copy the same XAML and change it for each object you want to apply the animation to. You’ll get into a deeper trap if you need to create an animation which should be different depending on the object this animation is applied to.

Based on the above, we’ve decided to come up with a different way to handle animations in Silverlight. We need a simple yet powerful way to reuse animations for different sets of objects. We also need a way to dynamically add animation effects to Silverlight objects.

In this article, we’ll cover some implementation details of how this problem can be solved.

Creating Simple Storyboards

As you probably know, Silverlight animations are handled by the Storyboard class. Creating a storyboard in XAML is easy, e.g., if you need to create a fade in animation, you would normally use the following piece of XAML code:

<Storyboard x:Name="fadeIn">
    <DoubleAnimation 
      Storyboard.TargetName="fadeInEffect" 
      Storyboard.TargetProperty="(UIElement.Opacity)"
      From="0"
      To="1"
      SpeedRatio="3">
    </DoubleAnimation>
</Storyboard>

Here, we use the DoubleAnimation element to animate the UIElement.Opactiry property from a 0 value to 1 with SpeedRatio set to 3. The Storyboard.TargetName attribute is used to specify the target object for the animation.

There are several other types of animation elements which can be created inside storyboards, e.g., we can also use the DoubleAnimationUsingKeyFrames element and create several SplineDoubleKeyFrame elements inside.

Now, if we want to apply this animation to a different object, or if we want to change some of the animation parameters, then we would need to copy this XAML and change it to suite our needs – and this is not what we want to achieve in the end.

Let’s consider another example of animation created using XAML code: a grow-effect XAML may look like this:

<Storyboard x:Name="grow">
 <DoubleAnimation 
 Storyboard.TargetName="growEffect" 
Storyboard.TargetProperty="(UIElement.RenderTransform).
          (TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
 From="1"
 To="1.5"
 SpeedRatio="3">
</DoubleAnimation>

<DoubleAnimation
Storyboard.TargetName="growEffect" 
Storyboard.TargetProperty="(UIElement.RenderTransform).
          (TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
  From="1"
  To="1.5"
  SpeedRatio="3">
 </DoubleAnimation>
</Storyboard>

Note that if we want to animate an element’s scale, then our target element should have appropriate transforms inside its RenderTransform property:

<Border.RenderTransform>
 <TransformGroup>
  <ScaleTransform ScaleX="1" ScaleY="1">
  </ScaleTransform>
 </TransformGroup>
</Border.RenderTransform>

Now, we can reference the ScaleTransform property via this string: (UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX).

Instead of creating animations purely in XAML, we can easily use procedural code. This might sound like a bad idea, but it’s not. Creating storyboards in procedural code is the most powerful way to create and reuse Silverlight animations.

Let’s consider some procedural code showing how we can create animations dynamically. The following code shows how a Storyboard object can be created in procedural code:

Storyboard storyboard = new Storyboard();

DoubleAnimation animation = new DoubleAnimation();
animation.From = 0;
animation.To = 1;
animation.SpeedRatio = 3;

Storyboard.SetTarget(animation, target);
Storyboard.SetTargetProperty(animation, "(UIElement.Opacity)");
storyboard.Children.Add(animation);

The code presented above is equivalent to the XAML code we created. However, this procedural code gives us some more flexibility, and allows code reuse. In other words, we can now create parameters for the From, To, and SpeedRatio properties and use any values we need.

Note that we call the SetTarget and SetTargetProperty static methods on the Storyboard class to set the target element and the target property for the double animation element. The last line of code adds a double animation element to the Storyboard object.

In order to run the animation, we’ll need to add the storyboard to our target framework element. Here is how we can do this:

target.Resources.Add(storyboard);

To start the animation, we just call Begin on the Storyboard instance.

Dynamic Effect Class

Let’s create a dynamic effect class which would be useful for creating storyboards dynamically, adding them to target framework elements and removing when animation is completed.

Here is the code of the DynamicEffect class:

public abstract class DynamicEffect
{
  FrameworkElement target;
  Storyboard storyboard;

  public DynamicEffect()
  {
  }

  protected abstract Storyboard CreateStoryboard(FrameworkElement target);

  protected virtual void Add(FrameworkElement target)
  {
    this.target = target;
    storyboard = CreateStoryboard(target);
    storyboard.Completed += new EventHandler(OnCompleted);
    target.Resources.Add(storyboard);
  }
  protected virtual void Remove()
  {
    if (target == null)
      return;
    if (storyboard == null)
      return;
    target.Resources.Remove(storyboard);
    target = null;
    storyboard = null;
  }
  protected virtual void OnCompleted(object sender, EventArgs e)
  {
    Remove();
    if (Completed != null)
      Completed(sender, e);
  }

  public virtual void Start(FrameworkElement target)
  {
    Add(target);
    storyboard.Begin();
  }
  public virtual void Stop()
  {
    if (target == null || storyboard == null)
      return;
    storyboard.Stop();
    Remove();
  }

  public event EventHandler Completed;
}

The DynamicEffect class defines the Start and Stop public methods to start and stop our effect, and there is also a useful Completed event defined.

The Start method will add an effect’s storyboard to the target framework element, and then call Begin to start animation. In turn, the Stop method will call Stop on the effect’s storyboard and then remove it from the target element.

All we need is just to create a descendant effect class and override its CreateStoryboard virtual method.

Fade In and Fade Out Effects

Here is how we would create the FadeEffect class:

public class FadeEffect : DynamicEffect
{
  double from;
  double to;
  double speed;

  public FadeEffect(double from, double to, double speed)
  {
    this.from = from;
    this.to = to;
    this.speed = speed;
  }

  protected override Storyboard CreateStoryboard(FrameworkElement target)
  {
    Storyboard result = new Storyboard();
    
    DoubleAnimation animation = new DoubleAnimation();
    animation.From = from;
    animation.To = to;
    animation.SpeedRatio = speed;
    
    Storyboard.SetTarget(animation, target);
    Storyboard.SetTargetProperty(animation, "(UIElement.Opacity)");

    result.Children.Add(animation);

    return result;
  }
}

Creating the fade-in and fade-out effects would be pretty straightforward.

The fade-in effect:

public class FadeInEffect : FadeEffect
{
  public FadeInEffect()
    : base(0.0, 1.0, 3.0)
  {
  }
}

The fade-out effect:

public class FadeOutEffect : FadeEffect
{
  public FadeOutEffect()
    : base(1.0, 0.0, 3.0)
  {
  }
}

Here is an example code for creating a fade in effect and applying it:

FadeInEffect effect = new FadeInEffect();
effect.Start(target);

Now, you can apply fade in and fade out effects to any number of framework elements, and no need to copy your XAML code :-)

Conclusion

The sample code for this article contains several animation effects created using XAML code.

In this brief article, we’ve covered some simple dynamic effects; however, it is possible to create more complex effects with animation of the transforms and clip properties. It is also possible to chain simple effects to achieve some complex functionality, e.g., creating carousel effects.

I plan to post more articles regarding Silverlight animation effects, please let me know what you would want to see in future articles.

Points of Interest

  • Adding animations for transforms and clip properties.
  • Creating animation chains.
  • Using split key frames to create non linear animation effects.

History

  • March 21, 2008: Initial release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here