views:

689

answers:

2

With reference to the Software Project I am currently working on.

I have the below methods that basically move a canvas with a Timer:

DispatcherTimer dt = new DispatcherTimer(); //global
public void Ahead(int pix)
    {
            var movx = 0;
            var movy = 0;
            dt.Interval = TimeSpan.FromMilliseconds(5);
            dt.Tick += new EventHandler((object sender, EventArgs e) =>
            {
                if (movx >= pix || movy >= pix)
                {
                    dt.Stop();
                    return;
                }
                Bot.Body.RenderTransform = new TranslateTransform(movx++, movy++);
            });
            dt.Start();
    }
public void TurnLeft(double deg)
    {

        var currAngle = 0;
        dt.Interval = TimeSpan.FromMilliseconds(5);
        dt.Tick += new EventHandler(delegate(object sender, EventArgs e)
        {
            if (currAngle <= (deg - (deg * 2)))
            {
                dt.Stop();
            }
            Bot.Body.RenderTransform = new RotateTransform(currAngle--, BodyCenter.X, BodyCenter.Y);
        });
        dt.Start();
    }

Now, from another library, these methods are called like such:

public void run()
{
    Ahead(200);
    TurnLeft(90);
}

Now of course, I want these animations to happen after another, but what is happening is that the dt.Tick event handler of the DispatchTimer is being overwritten when the second method (in this case, TurnLeft(90)) is invoked and thus, only the second method gets executed as it should.

I need to create some sort of queue that will allow me to push and pop methods to that queue so that dt (the DispatchTimer timer) executes them one by one...in the order they are in the 'queue'

Any way I can go about doing this ? Am I on the right track here, or completely off course?

+1  A: 

When you call Invoke() or BeginInvoke() on the Dispatcher, the operation will be queued up and run when the thread associated with the Dispatcher is free. So instead of using the Tick event, use the overload of Dispatcher.Invoke that takes a Timespan.

But I need the tick event to animate the movement.
Andreas Grech
+1  A: 

I have fixed this problem by myself. What I did was create a global Queue of type Delegate and instead of executing the methods directly, I add them to this queue.

Then I would have a separate thread in the constructor that will dequeue methods one by one and executing them:

    Queue<TimerDelegate> eventQueue = new Queue<TimerDelegate>();

    public Vehicle(IVehicle veh, Canvas arena, Dispatcher battleArenaDispatcher)
    {
         DispatcherTimer actionTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(100) };
         actionTimer.Tick += new EventHandler(delegate(object sender, EventArgs e)
    {
        if (IsActionRunning || eventQueue.Count == 0)
        {
            return;
        }
        eventQueue.Dequeue().Invoke(new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(5) });
    });
    actionTimer.Start();
    }

    public void TurnRight(double deg)
    {
        eventQueue.Enqueue((TimerDelegate)delegate(DispatcherTimer dt)
        {
            IsActionRunning = true;
            var currAngle = 0;
            dt.Tick += new EventHandler(delegate(object sender, EventArgs e)
            {
                lock (threadLocker)
                {
                    if (currAngle >= deg)
                    {
                        IsActionRunning = false;
                        dt.Stop();
                    }
                    Rotator_Body.Angle++;
                    currAngle++;
                }
            });
            dt.Start();
        });
    }
Andreas Grech
A sequencer! Great, thanks!
discorax