Reputation: 11
I have this (probably trivial problem). Im moving cards on form and in one process I need to wait, till card finishes moving (and is added into CardDeck class). For class design reasons I cant add card to new Deck imidietely. All I need is to wait with continuing in code for several ticks on timer (which is running on background). I found waiting routine here on Stackoverflow, but it dosnt work in this case and Im lost in using Process. Is there any simple way to wait some miliseconds, while programm is still running (timer ticking, cards moving on each tick). Im not sure if this can be done without threading, but I hope it is.
private void buCompW1W2_Click(object sender, EventArgs e) {
//starts moving card to new position
DeckPOne.MoveCardFromTopToTop(WarPOne);
DeckPTwo.MoveCardFromTopToTop(WarPTwo);
//code I hope to enter to delay next steps
Stopwatch stopwatch = Stopwatch.StartNew();
while (true) { //AwaitingReceiving indicates is Deck expects to receive card, 0 means, card is already there
if (WarPOne.AwaitingRecieving == 0 && WarPTwo.AwaitingRecieving == 0)
break;
}
//this test must be done after cards arrive to new place, else its error (-1)
//test compares cards in WarPOne and WarPTwo, but cards are not there yet (cards are waiting for timer tick to change position etc.) so it returns
//en error, mechanicaly done it works like intended
switch (CompareCards(WarPOne.TopCard, WarPTwo.TopCard)) {
case -1: tbRecord.Text += "\n error comparing"; break;
case 1: tbRecord.Text += "\n P1 won."; break;
case 2: tbRecord.Text += "\n P2 won."; break;
case 0: {
tbRecord.Text += "\n WAR!";
for (int i = 0; i < 3; i++) {
DeckPOne.MoveCardFromTopToTop(WarPOne);
DeckPTwo.MoveCardFromTopToTop(WarPTwo);
}
}; break;
}
}
Upvotes: 0
Views: 363
Reputation: 104
You already accepted another answer, but DoEvents really isn't how this would be handled nowadays. Using "tasks" it would be really easy to move the work to a managed background thread and keep the UI responsive:
private void buCompW1W2_Click(object sender, EventArgs e)
{
Task t1 = Task.Run(() =>
{
//starts moving card to new position
DeckPOne.MoveCardFromTopToTop(WarPOne);
DeckPTwo.MoveCardFromTopToTop(WarPTwo);
//code I hope to enter to delay next steps
Stopwatch stopwatch = Stopwatch.StartNew();
while (true)
{ //AwaitingReceiving indicates is Deck expects to receive card, 0 means, card is already there
if (WarPOne.AwaitingRecieving == 0 && WarPTwo.AwaitingRecieving == 0)
break;
}
//this test must be done after cards arrive to new place, else its error (-1)
//test compares cards in WarPOne and WarPTwo, but cards are not there yet (cards are waiting for timer tick to change position etc.) so it returns
//en error, mechanicaly done it works like intended
switch (CompareCards(WarPOne.TopCard, WarPTwo.TopCard))
{
case -1: tbRecord.Text += "\n error comparing"; break;
case 1: tbRecord.Text += "\n P1 won."; break;
case 2: tbRecord.Text += "\n P2 won."; break;
case 0:
{
tbRecord.Text += "\n WAR!";
for (int i = 0; i < 3; i++)
{
DeckPOne.MoveCardFromTopToTop(WarPOne);
DeckPTwo.MoveCardFromTopToTop(WarPTwo);
}
}; break;
}
});
}
This would actually start the work and then return control to the user. So while this is running, the user could click the button again. If this not what you want, you should disable the button until the task is finished. This could be done by adding
buCompW1W2.IsEnabled = false;
at the beginning of the method and
Dispatcher.Invoke(() => buCompW1W2.IsEnabled = true);
at the end of the task. You need to use the dispatcher on the second call, because UI elements can only be accessed from the UI thread.
Upvotes: 0
Reputation: 457
When you do this
while (true) {
}
on your main thread, There are lot of chances that your timer will be stuck because CLR gives preference to the Main/UI thread than to a timer or a background thread.
All the signals like timer tick,etc will be on MessageQueue and will not be processed until your Main thread is done .
You have two choices
Put
While(true)
{
if (WarPOne.AwaitingRecieving == 0 && WarPTwo.AwaitingRecieving == 0)
break;
Application.DoEvents(); // worst thing to do, but it works, flushes the message queue
}
else go for threading, Latest feature in threading called Task is robust and can make things easier for you
Upvotes: 1
Reputation: 1051
If you really want to just wait for some timer ticks, why don't you subscribe to the timer Elapsed
event and wait until "several" ticks have passed? (assuming you are talking about standard timers)
However, notifying the waiting component when the card finally arrives in the deck would possibly be a better option. You could use something like the AutoResetEvent provided by the framework or fire an CardReceived
event in the CardDeck class when a new card arrives, which the waiting component could subscribe to.
Upvotes: 0