tags:

views:

211

answers:

1

I've been teaching myself WPF through Sells/Griffiths' "Programming WPF", and I've found it a great resource, but I'm trying to take some of the concepts they've introduced me to and go a step further, and I'm running into a conceptual snag on how to put the pieces together to accomplish what I'm trying to do.

In this exercise, I'm trying to create self-terminating animations; FrameworkElements that are created by Events, perform an animation, and then delete themselves. I'm having problems figuring out how to call back to the parent FrameworkElement from the animation.Completed event.

I asked this question originally just using DoubleAnimations that were uncontained and not part of the Storyboard. I have since added the Storyboard, and made the Storyboard and rectangle resources so they can be reused easily.

Here's what I have so far:
.xaml:

<Window.Resources>
    <Storyboard x:Key="GrowSquare" x:Shared="False">
        <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" By="-50" Duration="0:0:2"/>
        <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" By="-50" Duration="0:0:2"/>
        <DoubleAnimation Storyboard.TargetProperty="(Ellipse.Width)" By="100" Duration="0:0:2"/>
        <DoubleAnimation Storyboard.TargetProperty="(Ellipse.Height)" By="100" Duration="0:0:2"/>
    </Storyboard>
    <Rectangle x:Key="MyRect" x:Shared="False" Width="20" Height="20">
    </Rectangle>
</Window.Resources>
<Canvas x:Name="myCanvas" MouseMove="myCanvas_MouseMove" Background="White"/>

.cs:

public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            lastFire = DateTime.Now;
        }

        DateTime lastFire;

        private void myCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            DateTime nowTime = DateTime.Now;
            TimeSpan T = nowTime.Subtract(lastFire);

            if (T.TotalMilliseconds > 200)
            {
                lastFire = nowTime;
                Random Rand = new Random();

                Rectangle myRect = (Rectangle)FindResource("MyRect");
                myRect.Fill = new SolidColorBrush(Color.FromRgb((byte)Rand.Next(256), (byte)Rand.Next(256), (byte)Rand.Next(256)));
                Point myLoc = e.GetPosition(myCanvas);
                Canvas.SetLeft(myRect, myLoc.X - 10);
                Canvas.SetTop(myRect, myLoc.Y - 10);
                myCanvas.Children.Add(myRect);

                Storyboard SB = (Storyboard)FindResource("GrowSquare");
                SB.Completed += new EventHandler(SB_Completed);
                SB.Begin(myRect);
            }

        }

        void SB_Completed(object sender, EventArgs e)
        {
            myCanvas.Children.RemoveAt(0);
        }
    }

This works, but not in the way I'd like it. Since the canvas is empty, and all animations are the same length, when an animation finishes, it will always be the one that was called on the first child of the canvas.

However, I'd like to implement animaitons that take a random amount of time, meaning that animations will not always start and end in the same order. Somehow in the SB_Completed event, I'd like to access the control that it was being called upon, but I can't seem to find the path to it yet.

Is there a way to get from the Media.Animation.ClockGroup that calls the SB_Completed event to the control that the animation is being called on?

A: 

change the line where you assign the event handler to this:

SB.Completed += (s,e) => myCanvas.Children.Remove(myRect);

Botz3000
I wasn't even thinking in that direction before. Thanks. That worked great.
Drew McGhie