Search code examples
c#timerdelaywaitsleep

How do i implement a time delay?


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);


Solution

  • 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:

    1. you set the content (but do not see/feel it)
    2. you start waiting 3 seconds
    3. you end waiting 3 seconds
    4. you set the content (but do not see/feel it)
    5. you exit your Button_Click method
    6. you actually see/feel the content change

    as 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:

    • use 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
    }
    
    • use 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();
    }