With reference to this programming game I am currently building.
I have a Class Library (dll) that will have a method Run
which will be composed of something like such:
public class MyRobot : Robot
{
public void Run(}
{
while (true)
{
Ahead(200); //moves the bot 200pixels
TurnLeft(90); //turns the bot by 90deg
}
}
}
In those methods (inherited from Robot
), the system will animate the robot using WPF (using BeginAnimation
or the DispatcherTimer
).
Now, the problem is that I don't a method to return (ie, move on to the next method) before completing the current one, because that will result in the animations taking place together, and when in an infinite loop (like the one above), that's especially not good.
My question is, what is the best way to prevent a method from returning before completing the animation ?
I currently have a bool
in the Robot
class (isActionRunning
) that be flagged to true
when an action starts running and then changes to false
in an animation callback (using the Completed
event if using BeginAnimation
).
At the end of each method (after invoking BeginAnimation
) I placed the following loop :
while (isActionRunning)
{
Thread.Sleep(200); //so that the thread sleeps for 200ms and then checks again if the animation is still running
}
This is so that the method won't return before the animation finishes.
But I feel that this is not the right way to do this.
Can anyone guide me to what's best to achieve this ?
Building a signalling device out of locks is craziness; just use the signalling device that already exists in the framework.
http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx
That is: thread one says "hey thread two, start this animation and signal me on this wait handle when you're done." Thread one then waits on the waithandle. Thread two starts the animation, and in its completion event, signals the waithandle. Thread one then wakes up again and says "hey thread two, start this other animation..."
I would do something similar to what you described. I recently worked on something where I called a bunch of asynchronous operations, and I wanted to wait for them all to complete before calling another operation. I created a collection to represent all of the operations currently executing and instead of adding items to the collection directly, I created methods for adding and removing. The remove method had logic that said "lock the collection, remove the key provided, and if empty call the next operation". You could create a similar mechanism like this where a collection scoped at the application or window keeps track of operations being executed. You add a key to the collection and pass this key to your async operation. When the async operation completes, lock the collection and remove the key. Then you can have a loop that blocks your method from returning while the collection contains the key (with optional logic for adding a timeout or any other additional ways where you might want the method to be able to return and not be blocked forever).
This might be overkill, but I have limited experience with this issue myself. For all I know, .Net might even have a canned solution to this problem that works with one or two lines of code.
Here's one option, it will only work if the Robot.Run code is running in a different thread than the UI thread doing the animations.
In the Robot.Ahead method (for example), use Dispatcher.Invoke (not BeginInvoke) to call the method that starts the animation, than add a lock on the robot with an empty block( lock(this) { } ).
In the method that starts the animation call Monitor.Enter(robot) before starting the animation
In the animation complete handler call Monitor.Leave(robot)
The result will be