I’ve discussed how to locate the UIElement associated with an animation’s Completed event a while back for WPF.
Here’s an update for how I do the same thing in Silverlight 2.0. The technique could be used in WPF with a few minor tweaks. I like this method rather than relying on a Storyboard (as I have better control over the completion of individual animations this way). Here’s a page on MSDN that describes various ways to work with animations programmatically in Silverlight.
The Completed event is raised when the animation timeline has ended. The event unfortunately passes only a reference to the sender (which is the Timeline). The EventArgs is empty.
Here’s a chunk of code that sets up an animation programmatically:
BitmapImage bmimg = sender as BitmapImage; Game.Dispatcher.BeginInvoke(delegate() { DoubleAnimation animation = new DoubleAnimation(); animation.To = 0.0; animation.From = 1.0; animation.Duration = new Duration(TimeSpan.FromSeconds(2 + Game.Randomizer.Next(5))); animation.SetValue(Page.ImageProperty, bmimg); animation.Completed += new EventHandler(animation_Completed); Image img = bmimg.GetValue(Page.ImageProperty) as Image; Storyboard sb = new Storyboard(); sb.Children.Add(animation); Storyboard.SetTarget(animation, img); Storyboard.SetTargetProperty(animation, new PropertyPath("Opacity")); sb.Begin(); }); }
The significant line above is the animation SetValue. Here, I’m using the power of the Dependency Object. I can attach new properties to the animation directly!
public static readonly DependencyProperty ImageProperty = DependencyProperty.RegisterAttached("Image", typeof(DependencyObject), typeof(Page), null);
I’ve created a new DependencyProperty (as an attached property) called ImageProperty. There’s not much meaning to the name — other than it makes sense in the context in which I’m using it in the larger application.
void animation_Completed(object sender, EventArgs e) { Timeline t = sender as Timeline; if (t != null) { BitmapImage img = t.GetValue(Page.ImageProperty) as BitmapImage; if (img != null) { // do something here... } } }
In the completed event, I retrieve the attached property’s value from the animation (which I’ve cast to one of the base types, a Timeline). Then, you could do whatever you want….