3

参考我目前正在从事的软件项目

我有以下方法,它们基本上使用计时器移动画布:

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();
    }

现在,从另一个库中,这些方法的调用方式如下:

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

现在当然,我希望这些动画一个接一个地发生,但是发生的情况是,当调用第二个方法(在本例中为)时,dt.Tick事件处理程序被覆盖,因此,只有第二个方法被执行应该。DispatchTimerTurnLeft(90)

我需要创建某种队列,允许我将方法推送和弹出到该队列,以便dtDispatchTimer计时器)一个接一个地执行它们……按照它们在“队列”中的顺序

我有什么办法可以做到这一点?我是在正确的轨道上,还是完全偏离了轨道?

4

2 回答 2

1

当您在 Dispatcher 上调用 Invoke() 或 BeginInvoke() 时,操作将排队并在与 Dispatcher 关联的线程空闲时运行。因此,不要使用 Tick 事件,而是使用采用 Timespan 的 Dispatcher.Invoke 的重载。

于 2009-02-08T07:01:46.167 回答
1

我自己解决了这个问题。我所做的是创建一个全局Queue类型Delegate,而不是直接执行这些方法,而是将它们添加到这个队列中。

然后我将在构造函数中有一个单独的线程,它将逐个出列方法并执行它们:

    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();
        });
    }
于 2009-02-10T05:33:50.233 回答