I'm 3 weeks into programming now so I tried to build a memory game.
Everything works fine except the delay. I've tried many different options but somehow the delay is at the end of the Button_Click
event.
If I click the first button it changes the content but when I click the 2nd
button no matter which if
statement triggers, the 2nd card doesn't show. The code works fine until the end of the event THEN the delay of 3 sec happens
What I want to achieve is that you can see the 2nd card a short amount of time before both cards are turned back over or disappear.
P.S. - It seems to work if i add a MessageBox
after the "delay"
but that's not the goal, so is there something like a wait for sync or something that I missed?
Code:
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
int index = ContainderGrid.Children.IndexOf(button);
mCounterSecondPic++;
button.Content = new BitmapImage(new Uri(mImgPath[mPairs[index]]));//change content
mPic[mCounterSecondPic-1] = mPairs[index];
button.IsEnabled = false;
if (mPic[0] == mPic[1] & mCounterSecondPic == 2)
{
mCounterSecondPic = 0;
new System.Threading.ManualResetEvent(false).WaitOne(3000); //wait for 3sec
ContainderGrid.Children.RemoveAt(mPairs.IndexOf(mPic[0]));
mPairs.RemoveAt(mPairs.IndexOf(mPic[0]));
ContainderGrid.Children.RemoveAt(mPairs.IndexOf(mPic[0]));
mPairs.RemoveAt(mPairs.IndexOf(mPic[0]));
}
if (mCounterSecondPic == 2 & mPic[0] != mPic[1])
{
mCounterSecondPic = 0;
new System.Threading.ManualResetEvent(false).WaitOne(3000);//wait for3 sec
ContainderGrid.Children.Cast<Button>().ToList().ForEach(resetbuttons =>
{
resetbuttons.IsEnabled = true;
resetbuttons.Content = new BitmapImage(new Uri(mCardBack));
});
}
ps: it seems to work if i add a messageBox before the "delay" but thats not the gole, so is there something like a wait for sync or something i missed?
MessageBox.Show("x");
new System.Threading.ManualResetEvent(false).WaitOne(3000);
Let's simplify the code:
private void Button_Click(object sender, RoutedEventArgs e)
{
button.Content = "START" //change content
new System.Threading.ManualResetEvent(false).WaitOne(3000); //wait for 3sec
button.Content = "FINISH" //change content
}
in this way you have the following timeline:
Button_Click
methodas you can see the content changes (at item1 and item4) have not happened immediately, but much later; this is due to fact that the UI thread was blocked inside the execution of Button_Click
method and hence was unable to refresh the graphic.
In order to achieve what you want, you have two options:
async/await
:private async void Button_Click(object sender, RoutedEventArgs e)
{
button.Content = "START" //change content
await Task.Delay(3000); //wait for 3sec asynchronously
button.Content = "FINISH" //change content
}
Dispatcher
:private void Button_Click(object sender, RoutedEventArgs e)
{
new Thread(() =>
{
Dispatcher.Invoke(() => button.Content = "START");
System.Threading.Thread.Sleep(3000);
Dispatcher.Invoke(() => button.Content = "FINISH");
}).Start();
}