reusing animations in Silverlight 1.0

Jaime Rodriguez
On Windows Phone, Windows Presentation Foundation, Silverlight and Windows 7

reusing animations in Silverlight 1.0

  • Comments 1

I have seen a few people create lots of animations to animate different objects instead of reusing existing storyboards..  When asked why they did that, they explain "I tried to reuse it but I got an "AG_E_RUNTIME_SETVALUE" when setting the property... 

Here are the details on how animations/storyboards work so you can reuse them:

  1. You will get AG_E_RUNTIME_SETVALUE if you try to set a value when storyboard is running:

    var sb = this.control.content.findName("reusable");
    sb.begin ();
    var animation = sb.Children.GetItem(0);        
    // This below will fail because the animation is running...  because the FillBehavior = HoldEnd
    animation["Storyboard.TargetName"] = 'rect2' ;
  2. To get around the error, you must either explicitly call storyboard.stop()  before trying to alter the storyboard, or use the FillBehavior="Stop"
    The problem w/ Stop is that the property you updated using the storyboard will go back to its original value ...  :(
  3. var sb = this.control.content.findName("reusable");
    sb.begin ();
    var animation = sb.Children.GetItem(0);        
    sb.stop ()   /// This makes line below no longer fail...   :)  but it undoes the work that previous ran animation had done..
    animation["Storyboard.TargetName"] = 'rect2' ;

  4. A way to 'hold' the value of the property you animated even after storyboard.stop () is to set it explicitly after you stopped it (duh jaime)... 
    There are fairly generic ways to do this..  (if running <Type>Animation,  then look at To value ... if running <Type>AnimationUsingKeyFrames  then look at last keyframe for that property and set property to that value...
var sb = this.control.content.findName("reusable");
// we wire completed...  so we know when to set the value.. 
sb.addEventListener("Completed", Silverlight.createDelegate ( this, this.onCompleted )); sb.begin ();
....
onCompleted : function ( sender , args ) 
    { 
        var animation = sender.Children.getItem(0); 
        var ctl = this.control.content.findName ( animation["Storyboard.TargetName"]) ; 
        if ( ctl != null ) 
        { 
            var keyframe = animation.KeyFrames.GetItem(animation.KeyFrames.Count-1); 
            sender.stop(); 
            ctl["Canvas.Left"] = keyframe.value ; 
        } 
        
    } , 
Now the value is maintained...   storyboard is stopped so it is reusable..


A sample (including source) for these snippets is here...  
for instructions:

  1. Click on any rectangle to see it animate..
  2. The demo begins with "Hold" checked because that is default behavior ( FillBehavior=HoldEnd)
  3. Click on the "stop animation before starting new one" to get around the AG_E_RUNTIME_SETVALUE
  4. Click on the "HoldEnd" to see the differences between  FillBehavior = HoldEnd  and FillBehavior = Stop
  5. Click on the "subscribe to event .. to set the value after animation has stopped"