So, I've got a little code for moving a control from one location/size on a form to another location/size. It does this via some slick animation code that I've got and the whole thing works quite well. The function you see below is where you start the animation process. One of the duties of this function is to queue subsequent calls to animate the same control. Now, if we receive a call to animate a specific control that is already being animated, we have two choices. We could either abort the first animation and start the second one, or we could wait until the first animation is finished and then start the second one. If we want to wait for the first animation to finish, then we need to somehow queue the second animation request and come back to it later. I'm doing this with an anonymous method. It's working very well.
Today I noticed that I might have a problem... even though there is no evident performance hit. When an animation finishes, you get the AnimationDone event. This event is handled elsewhere in the code to remove the animation from the list of active animations. It’s also used by the anonymous method to fire off the next animation in the queue. But the nature of an event is to call all of the handlers that have been attached to it. So, each time an animation finishes, we’re getting all of the queued animations trying to run again. Of course, we only need the first one in the queue to run. What happens is that the first one gets started and then all of the rest get called sequentially and re-inserted into the queue. I’m re-building my queue every time I access it. Ouch. Obviously, I’ll have to do something different here… but the anonymous delegate thing is still cool!
Note: Animations is a generic Dictionary collection (.net 2.0).
public
void Animate(Control ctrl, Point destination, Size endSize, AnimationType at, int totalFrames)
{
bool queued = false;
if(this.animations.ContainsKey(ctrl))
{
if(this.queueAnimations)
{
//queue this call with an anonymous delegate
this.animations[ctrl].DoneAnimating += delegate { Animate(ctrl, destination, endSize, at, totalFrames); };
queued = true;
System.Diagnostics.Debug.WriteLine("Animation Queued", "Animate()");
}
else
{
//abort mid-animation so we can start up a new one
//WARNING: this is NOT thread-safe!!!
this.animations[ctrl].Abort();
this.animations.Remove(ctrl);
}
}
if(!queued)
{
//
// There is some code in here to start the asynchronous animation
//
System.Diagnostics.Debug.WriteLine("Animation Started", "Animate()");
}
}
Here's the Debug output when I start four animations all at once:
Animate(): Animation Started
Animate(): Animation Queued
Animate(): Animation Queued
Animate(): Animation Queued
ca_DoneAnimating(): Animation Removed
Animate(): Animation Started
Animate(): Animation Queued
Animate(): Animation Queued
ca_DoneAnimating(): Animation Removed
Animate(): Animation Started
Animate(): Animation Queued
ca_DoneAnimating(): Animation Removed
Animate(): Animation Started
ca_DoneAnimating(): Animation Removed
[edited: 10/10/2005 - corrected a minor error]