WPF: построение очереди в потоке с таймерами - PullRequest
3 голосов
/ 08 февраля 2009

Что касается программного проекта , над которым я сейчас работаю .

У меня есть следующие методы, которые в основном перемещают холст с помощью таймера:

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 DispatchTimer перезаписывается, когда второй метод (в данном случае TurnLeft(90)) вызывается и, таким образом, только второй метод выполняется как следует.

Мне нужно создать какую-то очередь, которая позволит мне выдвигать и вставлять методы в эту очередь, чтобы dt (таймер DispatchTimer) выполнял их один за другим ... в том порядке, в котором они находятся в 'очередь'

Как я могу это сделать? Я на правильном пути или совсем не в курсе?

Ответы [ 2 ]

1 голос
/ 10 февраля 2009

Я сам исправил эту проблему. Я создал глобальный 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();
        });
    }
1 голос
/ 08 февраля 2009

Когда вы вызываете Invoke () или BeginInvoke () в Dispatcher, операция ставится в очередь и запускается, когда поток, связанный с Dispatcher, освобождается. Поэтому вместо использования события Tick используйте перегрузку Dispatcher.Invoke, которая занимает промежуток времени.

...