WPF:使用定时器在线程中构建队列

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

当然,我希望这些动画一个接一个地发生,但实际情况是当第二个方法(在这种情况下是 TurnLeft(90))被调用时,DispatchTimerdt.Tick 事件处理程序被覆盖,因此只有第二个方法按照应该的方式执行。
我需要创建某种队列,以便能够将方法推入和弹出到该队列中,以便 dtDispatchTimer 计时器)按照它们在“队列”中的顺序一次执行它们。
我该怎么做?我走对了还是完全偏离了轨道?
2个回答

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

但我需要tick事件来执行动画移动。 - Andreas Grech

1

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

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接