tags:

views:

95

answers:

2

I am doing some experimenting with threads, and made a 'control' method to compare against where all the processing happens in the UI thread. It should run a method, which will update a label at the end. This method runs four times, but the labels are not updated until all 4 have completed. I expected one label to get updated about every 2 seconds. Here's the code:

private void button1_Click(object sender, EventArgs e)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();

    UIThreadMethod(lblOne);
    UIThreadMethod(lblTwo);
    UIThreadMethod(lblThree);
    UIThreadMethod(lblFour);

    watch.Stop();
    lblTotal.Text = "Total Time (ms): " + watch.ElapsedMilliseconds.ToString();
}

private void UIThreadMethod(Label label)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();

    for (int i = 0; i < 10; i++)
    {
        Thread.Sleep(200);
    }
    watch.Stop();

    // this doesn't set text right away 
    label.Text = "Done, Time taken (ms): " + watch.ElapsedMilliseconds;
}

Maybe I'm just missing something basic, but I'm stuck. Any ideas? Thanks.

+2  A: 

You're blocking the UI thread by performing the sleep operations, which causes no redraws to happen. If you would sleep on another thread and Invoke the Label updates on the UI thread, then it should work as expected.

Thomas
Thanks, I can see it work as expected when using a different thread to run the `UIThreadMethod`, but why does `Thread.Sleep` prevent redraws? Would it be any different if it was just code that took 2 seconds to complete?
rosscj2533
Well, Thread.Sleep causes your current thread to do nothing. Because your current thread is the UI thread, the UI isn't performing any operations, and thus not doing any redraws.
Thomas
+2  A: 

Your UI thread is a single thread, not two threads. To get your UI to be responsive, you either have to put the work on another thread (generally with a BackgroundWorker), or tell the UI to repaint itself in the UI thread.

I always have to experiment when I do things like this, but the Control.Refresh method should do it:

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.refresh.aspx

Robert Harvey
Thanks, adding a `Refresh();` makes it work, but does that mean that any processing the UI thread does will always do the UI updating last?
rosscj2533
@rossch2533: Since it's one thread, yes, and since painting is a cumbersome task it's usually not performed unless it has to. When it comes to UI triggered events, painting is therefore performed after the methods complete, leaving valuable CPU cycles to the methods instead of "waisting them" on painting. You can of course bypass this, using the `Refresh` method for instance, but then you're the one deciding.
Patrick
@Patrick, thanks, that clears up the confusions I had that the answers weren't clear on.
rosscj2533