Create a Worker Thread for your Windows Form in C#

Threads and Delegates, Windows Forms

When performing a relatively heavy operation on your Windows Form, what often happens is that your application’s UI will freeze until the heavy operation completes. This is usually unacceptable because your application’s end user will think it crashed and probably try to close it. To solve this problem you need to run your heavy operation on a separate thread from that of your UI. This way you will be able to run your operation while also keep the end user informed of the progress from the UI. In this article I will show you how to do just that.

First let’s create a form with a textbox which displays the progress of the heavy operation, and two buttons, one to start the process and one to stop it.

Next we need to create our heavy operation method. For this example let’s just create a loop which iterates for 1 million times.

private void HeavyOperation()
{
    // Example heavy operation
    for (int i = 0; i <= 999999; i++)
    {
    }
}

Now let's declare our thread and a boolean flag used to stop the heavy operation. We must use the System.Threading namespace to access the Thread class.

// Declare our worker thread
private Thread workerThread = null;

// Boolean flag used to stop the 
private bool stopProcess = false;

Next in the start button event handler method, we will initialise the thread and tell it to run the HeavyOperation method.

private void btnStart_Click(object sender, EventArgs e)
{
    this.stopProcess = false;

    // Initialise and start worker thread
    this.workerThread = new Thread(new ThreadStart(this.HeavyOperation));
    this.workerThread.Start();
}

Your code should be able to compile and run but you won't see anything happening because we still have to display the heavy operation's progress on the UI.

This is where Delegates come in. In .NET a delegate is a form of type-safe function pointer. From the HeavyOperation method which is being run under the worker thread, we cannot access the UI thread directly because it would cause a cross-thread operation exception. This is because the UI thread and our worker thread are running independently of each other and cannot access objects which have not been created by themselves.

So to write to our status textbox which is on the UI from our worker thread, we must use a delegate. At the top of our class declare a delegate and an instance of the delegate as shown below:

// Declare a delegate used to communicate with the UI thread
private delegate void UpdateStatusDelegate();
private UpdateStatusDelegate updateStatusDelegate = null;

Next initialise the delegate in form load for example:

private void Form1_Load(object sender, EventArgs e)
{
    // Initialise the delegate
    this.updateStatusDelegate = new UpdateStatusDelegate(this.UpdateStatus);
}

As you can see in the above code, the delegate is being passed the method name UpdateStatus. This method will be used to display activity indication to the end user. Now let's create the method:

private void UpdateStatus()
{
    this.txtProgress.Text += "*";
}

Next, let's update our HeavyOperation method to call the delegate, which updates the status:

private void HeavyOperation()
{
    // Example heavy operation
    for (int i = 0; i <= 999999; i++)
    {
        // Check if Stop button was clicked
        if (!this.stopProcess)
        {
            // Show progress
            this.Invoke(this.updateStatusDelegate);
        }
        else
        {
            // Stop heavy operation
            this.workerThread.Abort();
        }
    }
}

As you can see, to call the delegate we are using the Invoke keyword, which executes the delegate on the UI thread, since we are calling Invoke from the this object.

And to add the final touch to our application, we must add an event handler for the stop button and set the stopProcess flag to true.

private void btnStop_Click(object sender, EventArgs e)
{
    this.stopProcess = true;
}

Now if you run the application and click on your start button, you will see the status textbox filling up with the "*" character. What's happening is your worker thread is iterating for 1 million times and for each iteration a star is written to the textbox using the delegate.

I hope you liked this article. Stay tuned for more soon.

Dave

DaveOnCSharp.com runs on the Thesis Theme


How smart is your Theme? How good is your support? Check out ThesisTheme for WordPress.

The Thesis Theme is one of the best Wordpress frameworks out there, especially if you understand software development, which since you're here you probably do. Thesis allows you to design post and page templates using a drag-and-drop system which gives you access to all the relevant page elements you would normally have to manually access through code. This is why understanding development techniques definitely helps, even though you don't need to write any code to get Thesis up and running.

So go check out the incredible features at DIYThemes and start using Thesis now!

11 comments… add one
  • Check out my other article on worker threads – Using the BackgroundWorker Component in C# – because it has a few advantages over the method I described above. 🙂

    Dave

  • Carlos Arias

    Awesome!

  • Iain

    (.Net newbie) Must/should you do something to guarantee updates to ‘stopProcess’ are visible across threads?

    In the Java memory model, we must use ‘volatile’ keyword to 100% guarantee the JVM won’t do anything too outrageously clever with optimization that could thwart your globally-shared-state.

  • james

    i like this tutorial alot. now i got a better understanding of threads. but one thing i do miss, is the complete source code, as i think its always good to see it all in all.
    also, you forgot to say that you named the TextBox txtProgress, other than that AWSOME !!!

  • Joe MacLeish

    Dave:
    I realize this is an old post but it is just what I need if I can make it work. This is my first thread. I wrote what I thought you said but I keep getting InvalidOperationException was unhandled. “Invoke or BeginInvoke cannot be called on a control until the window handle has been created.” This on the line “this.Invoke(this.updateStatusDelegate);” I suspect I am not doing things in the order you expected but I cannot see where the issue is. This would really help me if I could make it work. I am using MSVS C# 2008 Express and .NET 3.5. Is the full source available anywhere?
    I hope your still alive and thanks for any help.
    Joe

  • Joe MacLeish

    Dave:
    I retract. I rewote it from scratch and now it works fine. It looks the same to me but sometimes MSVS does things in the background that I can’t see or follow.
    thanks
    Joe

  • sankar

    I am having issue in this->Invoke(this->updateStatusDelegate);

  • Mangesh

    I am having same issue in this->Invoke(this->updateStatusDelegate);

  • Arun Kumar Kanojia

    Thanks for this awesome tutorial. It works for me…. You are great.

Leave a Comment