C# .NET – UI Threading Example


This is the simplest way to execute work in a separate thread and have it report back to the UI thread

When you’re creating a Windows Form Application using Visual C# 2008, there are some tricky threading issues that need to be dealt with in order to keep your application running smoothly.  Specifically, you have to be very aware of how your application does work.  If you simply create a worker function and then call it, it’s going to execute in the current thread, which is also the thread that’s handling the user interface.  The result really stinks because your UI will completely lock up until the worker thread is finished executing.  This is unacceptable in nearly all situations.

I want to show you what I believe is the absolute simplest way for executing a worker function in a separate thread while still allowing that separate thread to send information back to the main UI thread, whether it be to update a text box, a label, or a field in a datagridview.

In this example we’re going to click a button to launch our worker function, which will count from 1 to 15.  Our user interface will display each number as it counts. 

Also, please pardon the fact that I use ‘function’ and ‘method’ interchangeably in this post.  Technically, I should just be saying ‘method,’ but ‘function’ always slips out.

Download the entire Visual Studio project here: UI_Threading_Example_CSharp.zip

UI_Threading_ExampleUI_Threading_Example(2)

Let’s take a look at the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
using System;
using System.Windows.Forms;
using System.Threading;
 
namespace UI_Threading_Example
{
    //declare the delegate that we'll use to launch our worker function in a separate thread
    public delegate void workerFunctionDelegate(int totalSeconds);
 
    //declare the delegate that we'll use to call the function that displays text in our text box
    public delegate void poplateTextBoxDelegate(string text);
 
    public partial class Form1 : Form
    {
       public Form1()
       {
          InitializeComponent();
       }
 
       //this function will simply write text to our text box
       //this function will later be called from a worker thread through the use of a delegate using the Invoke method on the form
       void populateTextBox(string text)
       {
          textBox1.Text = textBox1.Text + " " + text;
       }
 
       //this function simulates "work" by simply counting from 1 to totalSeconds
       void workerFunction(int totalSeconds)
       {
          for (int count = 1; count <= totalSeconds ; count++)
          {
             //we use this.Invoke to send information back to our UI thread with a delegate
             //if we were to try to access the text box on the UI thread directly from a different thread, there would be problems
             this.Invoke(new poplateTextBoxDelegate(populateTextBox), new object[] { count.ToString() });
             Thread.Sleep(1000);
          }
       }   
 
       //this function is executed when we click the first button in the windows form
       //this is the PROPER WAY to do work in a UI situation
       //the worker function is launched in a separate thread so that our UI will remain responsive while it does work
       private void buttonNewThread_Click(object sender, EventArgs e)
       {
          workerFunctionDelegate w = workerFunction;
          w.BeginInvoke(15, null, null);
       }
 
       //this function is executed when we click the second button in the windows form
       //it's an example of WHAT NOT TO DO because if we click this button
       //the UI will become completely unresponsive for 15 seconds while the worker fucntion is executed
       private void buttonCurrentThread_Click(object sender, EventArgs e)
       {
          workerFunction(15);
       }
 }

OK, so here’s what we’ve got.  In Visual Studio (I’m using Visual C# 2008) I’ve created a new Windows Form Application and then in the designer window I added a text box (called textBox1) plus two buttons (called buttonNewThread and buttonCurrentThread).

In the code window I created two functions:

1
2
void populateTextBox(string text)
void workerFunction(int totalSeconds)

plus a delegate for each function:

1
2
public delegate void poplateTextBoxDelegate(string text);
public delegate void workerFunctionDelegate(int totalSeconds);

The first function is responsible for writing text to our text box.  The second function is responsible for doing “work,” which in this case is just counting from 1 to 15 and calling the function (using a delegate) to display the count in our text box.  Additionally there are two other functions (buttonCurrentThread_Click and buttonNewThread_Click) which handle the button clicks from our UI:

What’s the deal with delegates in this example?

In order to launch a worker function in a separate thread we have to declare a delegate for that function.  The delegate declaration must be outside the class declaration, and the delegate for each function must have the same format as the function that it’s going to be used to call.  So for example, if your worker function has 3 parameters, your delegate must also have 3 parameters.  And in this example, we not only need a delegate to handle launching our worker function in a new thread, but we also need to declare a delegate that we’ll use from within the worker thread to call a function to update the text box on the UI thread.  It is NOT ok to try to update a text box in the UI from a different thread without the use of a delegate.  If you don’t believe me then give it a shot and you’ll see for yourself that the results are funky.

The WRONG way to execute the worker function (using the UI thread)

When you click the button to execute the worker function in the current thread, which is the same thread that handles the UI, then you’ll see that for 15 seconds you can’t do anything with the UI or even move the form window to a new location.  At the end of 15 seconds the UI becomes responsive again and you see a “15” in the text box.

1
2
3
4
5
//This is the WRONG way to do it
private void buttonCurrentThread_Click(object sender, EventArgs e)
{
   workerFunction(15);
}

The RIGHT way to execute the worker function (using a separate thread)

When you click the button to execute the worker function in a new thread, you watch the count from 1 to 15 displayed in the text box and the UI is not frozen.

Note that the null values are required by the BeginInvoke method.  If you have a function that requires more than one parameter, you would still pass all your parameters in first, followed by the two nulls.  In this example we’re effectively passing the value 15 to the worker function which will then execute for 15 seconds.

1
2
3
4
5
6
//This is the RIGHT way to do it
private void buttonNewThread_Click(object sender, EventArgs e)
{
   workerFunctionDelegate w = workerFunction;
   w.BeginInvoke(15, null, null);
}

The proper way to update the text box in the UI from the worker thread using the Invoke method of the main form

The format can definitely get a little confusing, but hopefully you can follow along and mimic it for your application.  Instead of accessing the text box directly from the worker thread, which will cause problems, we instead invoke a method (using a delegate) that accesses the text box. Note that our populateTextBox function has one parameter, which is a string.  We want to write the current count to the text box using that function, so we have to convert it to a string.  If we were passing multiple variables to the populateTextBox function, the format would still look the same, and we’d simply separate the variables inside the curly braces by a comma.

1
2
3
4
5
6
7
8
9
//update the text box by using a delegate to call a function on the UI thread that will do the update
void workerFunction(int totalSeconds)
{
   for (int count = 1; count <= totalSeconds ; count++)
      {
         this.Invoke(new poplateTextBoxDelegate(populateTextBox), new object[] { count.ToString() });
         Thread.Sleep(1000);
      }
}

, , ,

  1. #1 by Raj on November 14, 2009 - 9:58 pm

    Dont we need to put the method populateTextBox inside a lock ?

    void populateTextBox(string text)
    {
    lock(this)
    {
    textBox1.Text = textBox1.Text + ” ” + text;
    }
    }

    • #2 by doug on November 17, 2011 - 4:59 pm

      Raj – thanks for the comment. I am definitely not an expert, but I don’t think we need a lock here. In fact, you’ll find numerous articles on the web that specifically state to never lock(this).

      Additionally, I think it’s the case that when we use this.Invoke, we actually automatically put ourselves in a thread-safe situation. The Invoke method executes the method on the control’s thread, which I think means that even if you have 20 different threads simultaneously use this.Invoke, they will all get executed sequentially and safely. However, again I admit that I’m not an expert on the subject. Nevertheless, I’ve never run into a problem with the method used in the above code, so I feel pretty good about it being a safe/good way to handle the textbox update.

      I’m always open to learn new things, so if anyone has additional light to shed, please do.

      -Doug

  2. #3 by Al on November 23, 2009 - 3:04 pm

    i think the lock{} is only needed for shared variables. i.e. if you have more than one thread writing to that textbox. if there’s another thread writing to that same text box you want to make sure it waits until the first thread finishes. to keep concurrency.

  3. #4 by Frank on January 18, 2010 - 9:53 am

    Hi, I like the simplicity of your example. However, I wonder how the following situation should be resolved:

    If you start the “worker in a new thread” and close the form BEFORE it has completed, the application crashes.

    Any idea on how to deal with this situation?

  4. #5 by Jim on July 26, 2010 - 7:19 pm

    Hi Doug,

    Just a quick Thanks!! for posting your article. After digging through the C# 4.0 Nutshell book and numerous examples on the ‘net, yours is the first example that is straightforward, understandable, and actually worked when I used it as an example in my thread-to-UI update code. Jim

  5. #6 by doug on July 26, 2010 - 9:16 pm

    Glad to hear it, Jim! Thanks.

  6. #7 by francisco on September 1, 2010 - 4:10 pm

    i was stuck with my degree project because of the “only UI thread can modify UI elements” problem. thanks!! :)

  7. #8 by sunik on October 31, 2011 - 3:02 am

    Quoting Jim, since he pretty much said the exact same thing I wanted to say, plus couple of interesting findings;

    I use C# 2010 Express, and I noticed couple of things different from this example which was done in VC#2008:
    – using a direct call populateTextBox(count.ToString()); in workerFunction method using new thread doesn’t yield “funky” results; instead, it gives “InvalidOperationException” saying ‘textBox1’ cannot be “accessed from a thread other than the thread it was created on.”
    – the output of “wrong way” to execute worker function is different than one described here( At the end of 15 seconds the UI becomes responsive again and you see a “15″ in the text box.). Instead, at the end of 15 seconds, you see the whole series “1 2 3 4 (…) 15” appear at once.

    As per Frank’s concern, I found placing lock around worker function seem to make the problem go away. I am not at all sure if this is a legitimate solution, since removing the lock doesn’t necessarily bring the problem back; I’d love to see some1 answer his/my question someday.

    Thanks again Doug

    • #9 by doug on October 31, 2011 - 7:42 pm

      Interesting findings. Thanks for sharing.

      One point about preventing the exception when closing the form before the worker thread completes: Microsoft appears to acknowledge that this is expected behavior, if I’m reading the following page correctly.

      They say: “An exception might be thrown if the thread that should process the message is no longer active.”

      http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

      So, perhaps the best thing to do is put the this.Invoke call inside a try {} block. I haven’t tested that, but I’d imagine it might work.

      -Doug

  8. #10 by Balu on March 6, 2012 - 11:29 am

    So many thanks.. really helpful. I had been wondering how to have my COM port receive and send data simultaneously into a user form. I think, I can start off by tweaking your code here.. Cheers..

  9. #11 by Jey2002 on April 17, 2012 - 9:47 am

    Thank you so much for the great example.. keep up the good work

  10. #12 by Alan Galiwango on June 19, 2012 - 4:16 pm

    Thanks for this great example. Will use it to explain to my team the principles of UI Threading and what to avoid.
    To answer sunik’s question, we never want to have a random worker thread updating the main UI thread due to the possibility of deadlock and race conditions. This is why we explicitly do the invoke on “this” implying the main UI thread to do the updating of the controls.

  11. #13 by Gaurav Balyan on June 22, 2012 - 6:22 am

    Hi Doug,
    Thanks for such a great article.

    Can you please help me with this,
    i am building an application which sends bulk emails but as soon as i click send button the ui becomes unresponsive till it sends all the email in the list.
    i have tried your example but still it is unresponsive,can you suggest me anything.
    thanks

    • #14 by doug on June 22, 2012 - 6:43 pm

      Gaurav – if you want to post the code somewhere for me to look at, I’ll see if I can help.

      -Doug

  12. #15 by hetal on December 24, 2012 - 7:42 am

    nice code solved my problem…

  13. #16 by srinivasulu on March 30, 2013 - 7:40 am

    very nice and solved my problem

  14. #17 by Tampa Teacher on April 3, 2013 - 8:03 pm

    A terrific and simple example of how to do something so basic in Windows Forms.

    All examples should be this direct and easy to follow.

  15. #19 by Alan Hoffmann-Hansen on March 6, 2014 - 9:35 am

    Is it not necessary to start a thread with Thread MyThread = new Thread (new ThreadStart (populate)); MyYread.start ?

    • #20 by doug on March 6, 2014 - 11:31 am

      The Thread class usage that you suggest is not required for the delegate invocation that is performed in this tutorial. Either will yield you a new thread. Since I wrote the original blog posting, the .NET framework has added significant improvements to threading, and now there are even more ways to do it than in the past, with some of the newest methods being extremely simple. A thread created with delegate invocation will be part of the system thread pool, but using the Thread class to create a new thread will keep it apart from the thread pool. This may or may not matter to you if you’re creating just a few threads here or there, but if you’re getting involved in a highly threaded application, then it becomes more relevant to make your selection according to your needs. For example, if you choose to limit the number of threads in the thread pool to 10, and then you use delegate invocation to spin up 11 threads, the 11th will queue until one of the first 10 completes. However, with the Thread class you won’t experience any queuing.

      -Doug

(will not be published)