2

I have a WPF app and I want to sleep for a second before displaying certain info on screen. So its. 1. Click a button.

  1. Sleep 1 sec.
  2. Display a label.
  3. Sleep 1 sec.
  4. Display a label.
  5. etc etc

    private void RunTest()
    {
        clearTable();
    
        System.Threading.Thread.Sleep(1000);
    
        this.Cursor = Cursors.Wait;
    
        Label_OS_Result.Content = operatingSystem;
        Image_OS.Visibility = Visibility.Visible;
    
        System.Threading.Thread.Sleep(1000);
    
        Label_CPU_Result.Content = procName;
        Image_CPU.Visibility = Visibility.Visible;
    
        System.Threading.Thread.Sleep(1000);
     }
    

But when I click my button it seems to wait for a few seconds and then displays everything all at once.

Whats going on here??

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Harry Boy
  • 4,159
  • 17
  • 71
  • 122
  • That's what timers were made for. Take a look at DispatcherTimer. – Clemens Dec 17 '13 at 12:44
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Dec 17 '13 at 12:44

4 Answers4

1

It is working as it is expected.

Thread.Sleep stops the execution of the current thread for specified amount of time. So, when you change the visibility of an image, it will make further calls to change the visibility in the framework, then it will try to draw it on screen (invalidates). When you sleep the thread before this operation finishes it will not have enough time to finish this operation. You are simply blocking the UI thread responsible of drawing something on the screen.

Beware that Thread.Sleep may not be the solution, it is better for you to have a look at DispatcherTimer or BackgroundWorkers.

daryal
  • 14,643
  • 4
  • 38
  • 54
  • Correct. The Sleep blocks your UI thread. You will can use async pattern of .NET 4.5. An similar example you can find [here](http://stackoverflow.com/questions/2565166/net-best-way-to-execute-a-lambda-on-ui-thread-after-a-delay): Task.Factory.StartNew(() => Thread.Sleep(1000)) .ContinueWith((t) =>(...) – dixus Dec 17 '13 at 12:46
1

You don't want to Thead.Sleep() on the thread displaying your GUI.

Instead, you should try await Task.Delay(). This is similar to sleep, but it won't block the GUI thread.

This will allow all the rendering to still happen, while delaying the visiblity changes for your labels.

poy
  • 10,063
  • 9
  • 49
  • 74
1

It is working as intended.

It may not be what you expected, but the problem here is your expectations.

What happens when you fiddle with properties on most visual controls, that should end up changing the appearance of the control, is first to make the internal adjustments to the controls properties (ie. data), and then trigger a redraw. To trigger the redraw, a message is usually posted to the message queue of the thread that owns this visual control.

This thread usually processes messages one at a time, be it a button click, mouse movement, or the paint messages that was just posted because you changed the image.

However, that thread is basically written like this (pseudo-code):

while (true)
{
    var message = GetNextMessageFromQueue();
    ProcessMessage(message);
}

The last time this loop was active, it started processing a message that ended up calling your code, the one that is now sleeping.

So basically, to get the message pump (the typical name of the code that implements this loop) to continue pumping messages, and thus process your paint message, is not to sleep.

You might want to separate your processing out to a different thread, or some other asynchronous way of doing things "in the background".

Note that you will get the same problem if you start doing any kind of lengthy processing in response to a button click or similar, without doing it on a background thread (or again, some other asynchronous way). The GUI will appear to have frozen.

This problem, however, is so common that Microsoft ended up building in special support for it in Windows. It used to be that a window just seemed to hang. Now, however, if the message queue "fills up", Windows will fade out the windows and tack on a caption to it indicating that it has stopped responding. Not a solution, but slightly better.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
0

Sleep function is behaving correct.

Better you use a Timer to do so,

    // Declare it in the constructor of the class
    int level = 0;
    Timer timer = new Timer
    timer.Interval = 1000;
    timer.Tick +=new EventHandler(timer_Tick);

private void timer_Tick(object sender, EventArgs e)
{
    timer.Stop();
    if (level == 0)
    {
        Label_OS_Result.Content = operatingSystem;
        Image_OS.Visibility = Visibility.Visible;
        ++level;
    }
    else if (level == 1)
    {
        Label_CPU_Result.Content = procName;
        Image_CPU.Visibility = Visibility.Visible;
        ++level;
    }
    else if (level > 1)
    {
        this.Cursor = Cursors.Default;
        return;
    }
    timer.Start();
}
private void RunTest()
{
    clearTable();

    //System.Threading.Thread.Sleep(1000);
    timer.Start();
    this.Cursor = Cursors.Wait;
}
Abu Umer
  • 11
  • 2
  • Have you tried running this? This will throw runtime exception since you can't access UI element from background thread. Timer tick event is called on background thread and not on UI thread. – Rohit Vats Dec 17 '13 at 13:07
  • Yes, it works fine and there is no such exception. I have not executed Tick Event in Thread so you can use it. – Abu Umer Dec 26 '13 at 10:20