WPF: возвращение метода ПОСЛЕ анимации завершена - PullRequest
0 голосов
/ 11 марта 2009

Применительно к этой программируемой игре Я сейчас строю.

У меня есть библиотека классов (dll), которая будет иметь метод Run, который будет состоять из чего-то вроде:

public class MyRobot : Robot 
{
    public void Run(} 
    {
        while (true) 
        {
           Ahead(200); //moves the bot 200pixels
           TurnLeft(90); //turns the bot by 90deg 
        }
    }
}

В этих методах (унаследованных от Robot) система будет анимировать робота с помощью WPF (используя BeginAnimation или DispatcherTimer).

Теперь проблема в том, что я не могу вернуть метод (т. Е. Перейти к следующему методу) перед завершением текущего, потому что это приведет к тому, что анимация будет происходить вместе и в бесконечном цикле. (как показано выше), это особенно не хорошо.


У меня такой вопрос, как лучше всего предотвратить возврат метода до завершения анимации ?

В настоящее время у меня есть bool в классе Robot (isActionRunning), который помечается как true, когда начинается действие, а затем изменяется на false в обратном вызове анимации (с использованием Completed событие при использовании BeginAnimation).

В конце каждого метода (после вызова BeginAnimation) я поместил следующий цикл:

while (isActionRunning) 
{
    Thread.Sleep(200); //so that the thread sleeps for 200ms and then checks again if the animation is still running 
}

Это значит, что метод не вернется до завершения анимации.

Но я чувствую, что это неправильный способ сделать это.

Кто-нибудь может подсказать мне, как лучше всего этого добиться?

Ответы [ 3 ]

5 голосов
/ 01 апреля 2010

Создание сигнализатора из замков - это безумие; просто используйте сигнальное устройство, которое уже существует в рамках.

http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx

То есть: первый поток говорит: «Привет второй поток, запустите эту анимацию и сообщите мне об этом на ручке ожидания, когда вы закончите». Поток один затем ждет на ручке ожидания. Второй поток запускает анимацию и в своем событии завершения сигнализирует о ручке ожидания. Поток один, затем снова просыпается и говорит: «Привет, поток второй, запусти эту другую анимацию ...»

3 голосов
/ 11 марта 2009

Вот один из вариантов, он будет работать только в том случае, если код Robot.Run выполняется в потоке, отличном от потока пользовательского интерфейса, выполняющего анимацию.

В методе Robot.Ahead (например) используйте Dispatcher.Invoke (не BeginInvoke) для вызова метода, запускающего анимацию, затем добавьте блокировку робота с пустым блоком (lock (this) {}) .

В методе, который запускает анимацию, вызывается Monitor.Enter (робот) перед запуском анимации

В анимации завершен вызов обработчика Monitor.Leave (робот)

Результат будет

time      robot thread          UI thread  
  |       ---------------       --------------  
  |       call Invoke    --->  
  |                             lock robot (Monitor.Enter)  
  |                             begin animation  
  |       Invoke returns <---   return  
  |       lock(this)            (animation running)  
  |       (wait for lock  
  |       to become available)  
  |  
  |                             Animation complete  
  |                             release lock (Monitor.Exit)  
  |       (lock available,  
  |       continue running)  
  |       Release lock (exit lock block)  
  |       Return and start next  
  |       movement  
  \/  
0 голосов
/ 11 марта 2009

Я бы сделал что-то похожее на то, что вы описали. Недавно я работал над чем-то, что я назвал набором асинхронных операций, и я хотел дождаться их завершения, прежде чем вызывать другую операцию. Я создал коллекцию для представления всех выполняемых в данный момент операций, и вместо того, чтобы добавлять элементы в коллекцию напрямую, я создал методы для добавления и удаления. У метода remove была логика, которая гласила: «Заблокируйте коллекцию, удалите предоставленный ключ и, если он пуст, вызовите следующую операцию». Вы можете создать подобный механизм, подобный этому, где коллекция, находящаяся в области приложения или окна, отслеживает выполняемые операции. Вы добавляете ключ в коллекцию и передаете его в асинхронную операцию. Когда асинхронная операция завершится, заблокируйте коллекцию и удалите ключ. Тогда у вас может быть цикл, который блокирует возврат вашего метода, в то время как коллекция содержит ключ (с необязательной логикой для добавления тайм-аута или любых других дополнительных способов, когда вы можете захотеть, чтобы метод мог возвращаться и не блокироваться вечно).

Это может быть излишним, но я сам ограничен в этом вопросе. Насколько я знаю, .Net может даже иметь консервативное решение этой проблемы, которое работает с одной или двумя строками кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...