2009-03-10 8 views
0

Mit Bezug auf this programming game baue ich gerade.WPF: Zurückgeben einer Methode, nachdem eine Animation beendet wurde

Ich habe eine Klassenbibliothek (DLL), die eine Methode hat Run, die wie so etwas zusammengesetzt sein werden:

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

Bei diesen Verfahren (geerbt von Robot), wird das System der Roboter animiert Verwenden von WPF (unter Verwendung von BeginAnimation oder DispatcherTimer).

Nun, das Problem ist, dass ich keine Methode zurückgeben (dh, mit der nächsten Methode weitermachen) vor dem Abschluss der aktuellen, denn das wird dazu führen, dass die Animationen zusammen stattfinden, und wenn in einer unendlichen Schleife (wie die oben), das ist besonders nicht gut.


Meine Frage ist, was ist der beste Weg, um ein Verfahren von der Rückkehr vor dem Abschluss der Animation zu verhindern?

Ich habe derzeit ein bool in der Robot Klasse (isActionRunning), das zu true gekennzeichnet werden, wenn eine Aktion beginnt zu laufen und wechselt dann in false in einer Animation Callback (das Completed Ereignis zu verwenden, wenn mit BeginAnimation).

Am Ende jeder Methode (nach BeginAnimation Aufrufen) I platziert, um die folgenden Schleife:

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

Dies ist so, dass das Verfahren, bevor die Animation endet nicht zurückkehren wird.

Aber ich fühle, dass dies nicht der richtige Weg ist, dies zu tun.

Kann mir jemand sagen, was das Beste ist, um dies zu erreichen?

Antwort

3

Hier ist eine Option, sie funktioniert nur, wenn der Robot.Run-Code in einem anderen Thread ausgeführt wird als der UI-Thread, der die Animationen ausführt.

Verwenden Sie in der Robot.Ahead-Methode (z. B.) den Dispatcher.Rufen Sie (nicht BeginInvoke) auf, um die Methode aufzurufen, die die Animation startet, und fügen Sie dem Roboter eine Sperre mit einem leeren Block hinzu (lock (this) {}).

Bei dem Verfahren, das die Animation Anruf Monitor.Enter beginnt (Roboter), bevor die Animation

In der Animation komplette Handler aufrufen Monitor.Leave (Roboter) Start

Das Ergebnis wird sein

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

Ausgezeichnet, das ist super. Ich habe jetzt meine Logik geändert, um das zu implementieren, was Sie vorgeschlagen haben, anstelle der Schleife while (isActionRunning). –

+1

Das ist * verrückt *. Wenn Sie warten wollen, bis ein Thread einem anderen signalisiert, dass seine aktuelle Arbeit erledigt ist, bauen Sie kein Signal aus den Sperren auf, ** benutzen Sie einfach ein Signal **. Es gibt bereits ein Objekt, das dies im Rahmen tut; benutze es einfach. http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx –

+0

@Eric Ich erinnere mich nicht, warum ich Sperren (ich schrieb das vor einem Jahr immerhin), Es ist möglich, dass ich hatte Ein guter Grund - aber mir fällt nichts ein, also sind Signale hier wohl die richtige Lösung. Aus meiner Erfahrung sind Mutex-Locks jedoch sehr robust und vorhersehbar, während Signale jede zukünftige Codeänderung in eine schwer reproduzierbare Race-Bedingung verwandeln (ich musste einen C++ - Multi-Threading-Server unterhalten, für den Signale verwendet wurden Synchronisation - Signale haben so viele Fallstricke, dass es einfach nicht witzig ist) – Nir

0

Ich würde etwas tun, was Sie beschrieben haben. Ich habe kürzlich an etwas gearbeitet, bei dem ich eine Reihe von asynchronen Operationen aufgerufen habe, und ich wollte warten, bis alle fertig sind, bevor ich eine andere Operation anrufe. Ich habe eine Sammlung erstellt, die alle derzeit ausgeführten Operationen darstellt, und anstatt Elemente direkt zur Sammlung hinzuzufügen, habe ich Methoden zum Hinzufügen und Entfernen erstellt. Die Methode remove hatte eine Logik, die besagt: "Sperren Sie die Sammlung, entfernen Sie den bereitgestellten Schlüssel und, falls leer, rufen Sie die nächste Operation auf". Sie könnten einen ähnlichen Mechanismus wie diesen erstellen, bei dem eine Sammlung in der Anwendung oder im Fenster die ausgeführten Operationen verfolgt. Sie fügen der Sammlung einen Schlüssel hinzu und übergeben diesen Schlüssel an Ihren asynchronen Vorgang. Wenn die asynchrone Operation abgeschlossen ist, sperren Sie die Sammlung und entfernen Sie den Schlüssel. Dann können Sie eine Schleife verwenden, die die Rückgabe der Methode blockiert, während die Auflistung den Schlüssel enthält (mit optionaler Logik zum Hinzufügen eines Zeitlimits oder anderer Methoden, bei denen die Methode möglicherweise zurückkehren und nicht für immer blockiert werden kann).

Dies könnte Overkill sein, aber ich habe begrenzte Erfahrung mit diesem Thema selbst. Soweit ich weiß, könnte .Net sogar eine vorkonfektionierte Lösung für dieses Problem haben, die mit einer oder zwei Codezeilen funktioniert.

5

Der Aufbau eines Signalgeräts aus Schleusen ist verrückt; Verwenden Sie einfach das Signalgerät, das bereits im Framework existiert.

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

Das heißt: Faden man sagt: „Hey Thread zwei, diese Animation starten und mich Griff auf dieser Warte signalisieren, wenn Sie fertig sind.“ Thread eins wartet dann auf den Waithandle. Thread zwei startet die Animation und signalisiert bei ihrem Abschlussvorgang den Waithandle. Thread man wacht dann wieder auf und sagt "Hey three two, starte diese andere Animation ..."

+0

Hallo Eric, ich habe versucht wie du beraten, aber es funktioniert nicht für mich. Könnten Sie sich bitte diesen Thread ansehen: http://stackoverflow.com/questions/3420901/synchronous-blocking-animations-in-wpf Vielen Dank! Hat sonst noch jemand eine Lösung für das Problem dieses Threads gefunden? –