2009-03-10 8 views
0

En référence à this programming game Je construis actuellement.WPF: Retour d'une méthode APRÈS la fin d'une animation

J'ai une bibliothèque de classes (dll) qui aura une méthode Run qui sera composé de quelque chose comme par exemple:

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

Dans ces méthodes (héritée de Robot), le système d'animer le robot en utilisant WPF (en utilisant BeginAnimation ou DispatcherTimer). Maintenant, le problème est que je n'ai pas de méthode à retourner (c'est-à-dire que je passe à la méthode suivante) avant de terminer la méthode en cours, car les animations se dérouleront ensemble, et dans une infinité boucle (comme celle ci-dessus), ce n'est surtout pas bon.


Ma question est, quelle est la meilleure façon d'éviter une méthode de revenir avant la fin de l'animation?

J'ai actuellement un bool dans la classe Robot (isActionRunning) qui se trouve en position de true lorsqu'une action commence à courir, puis passe à false dans un rappel d'animation (en utilisant l'événement Completed si vous utilisez BeginAnimation).

A la fin de chaque méthode (après l'appel BeginAnimation) J'ai placé la boucle suivante:

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

Il en est ainsi que la méthode ne reviendra pas avant la fin de l'animation. Mais je pense que ce n'est pas la bonne façon de le faire.

Quelqu'un peut-il me guider vers ce qu'il y a de mieux pour y parvenir?

Répondre

3

Voici une option, cela ne fonctionnera que si le code Robot.Run s'exécute dans un thread différent du thread UI faisant les animations.

Dans la méthode Robot.Ahead (par exemple), utilisez Dispatcher.Appelez (pas BeginInvoke) pour appeler la méthode qui démarre l'animation, puis ajoutez un verrou sur le robot avec un bloc vide (lock (this) {}).

Dans le procédé qui commence l'appel d'animation Monitor.Enter (robot) avant de commencer l'animation

Dans l'animation gestionnaire complet appeler Monitor.Leave (robot)

Le résultat sera

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

Excellent, c'est génial. J'ai maintenant changé ma logique pour implémenter ce que vous avez suggéré, au lieu de la boucle while (isActionRunning). –

+1

Ceci est * fou *. Si vous voulez attendre qu'un thread signale à un autre que son travail actuel est terminé, ne construisez pas un signal de verrouillage, ** utilisez simplement un signal **. Il y a déjà un objet qui fait cela dans le cadre; il suffit de l'utiliser. http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx –

+0

@Eric Je ne me souviens pas pourquoi j'ai utilisé des verrous (j'ai écrit cela il y a un an après tout), il est possible que j'ai eu une bonne raison - mais je ne peux pas penser à tout, donc les signaux sont probablement la bonne solution ici. D'après mon expérience, les verrous de style mutex sont très robustes et prévisibles, alors que les signaux transforment chaque changement de code futur en condition de course difficile à reproduire (je devais maintenir un serveur multi-thread C++ utilisant des signaux pour synchronisation - les signaux ont tellement de pièges que ce n'est pas drôle) – Nir

0

Je ferais quelque chose de similaire à ce que vous avez décrit. J'ai récemment travaillé sur quelque chose où j'ai appelé un tas d'opérations asynchrones, et je voulais attendre qu'elles soient toutes terminées avant d'appeler une autre opération. J'ai créé une collection pour représenter toutes les opérations en cours d'exécution et au lieu d'ajouter directement des éléments à la collection, j'ai créé des méthodes pour ajouter et supprimer. La méthode de suppression avait une logique qui disait «verrouiller la collection, retirer la clé fournie, et si vide appeler l'opération suivante». Vous pouvez créer un mécanisme similaire à celui-ci, où une collection étendue à l'application ou à la fenêtre conserve une trace des opérations en cours d'exécution. Vous ajoutez une clé à la collection et transmettez cette clé à votre opération asynchrone. Une fois l'opération asynchrone terminée, verrouillez la collection et supprimez la clé. Vous pouvez ensuite avoir une boucle qui empêche votre méthode de retourner pendant que la collection contient la clé (avec une logique facultative pour ajouter un délai ou toute autre méthode supplémentaire pour laquelle la méthode peut retourner et ne pas être bloquée pour toujours).

Cela pourrait être exagéré, mais j'ai une expérience limitée de ce problème moi-même. Pour tout ce que je sais, .Net pourrait même avoir une solution en boîte à ce problème qui fonctionne avec une ou deux lignes de code.

5

Construire un dispositif de signalisation hors des verrous est une folie; il suffit d'utiliser le dispositif de signalisation qui existe déjà dans le cadre.

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

C'est: fil on dit « hey deux fils, commencez cette animation et me signal sur cette poignée d'attente lorsque vous avez terminé. » Thread one puis attend sur le waithandle. Thread deux démarre l'animation, et dans son événement d'achèvement, signale le waithandle. Thread one puis se réveille à nouveau et dit "hey thread deux, commencer cette autre animation ..."

+0

Bonjour Eric, j'ai essayé comme vous conseillé, mais ça ne marche pas pour moi. Pourriez-vous s'il vous plaît jeter un oeil à ce fil: http://stackoverflow.com/questions/3420901/synchronous-blocking-animations-in-wpf Merci beaucoup! Quelqu'un d'autre peut-être trouvé une solution pour le problème de ce thread? –

Questions connexes