Thursday, November 30, 2006

Update GUI controls in multi-threaded WinForm apps in .NET 2.0

.NET 2.0 by default doesn't allow code running in a separate thread to update controls created by the main GUI thread. So if you create a new thread, that thread cannot call Textbox1.Text = "Hello World" for example.

There are two ways around this - set the CheckForIllegalCrossThreadCalls flag to false. This will allow .NET 1.1 controls to work as they did under the 1.1 framework.

The proper way to do it (according to Microsoft) is to create a method to do the control update, then call that method (on the main thread) through a delegate.

Its always easiest to see some code example. In this example, I am hiding/showing the main form from a worker thread.

At the top of my form class I have the following:
delegate void SetFormVisibleCallBack(bool visible);


The actual method to set the Visible flag is:

private void SetFormVisible(bool visible)
{
if (this.InvokeRequired) /*returns true if we are calling the method from a worker thread.*/
{
SetFormVisibleCallBack visCB = new SetFormVisibleCallBack(SetFormVisible);
this.Invoke(visCB, new object[] { visible });
}
else
{
this.Visible = visible;
}
}

If called from a worker thread, SetFormVisible Invoke()'s the main thread to call the SetFormVisible method again. When it does so, this.InvokeRequired will be false, allowing the Visible property to be directly set.

Now, to set the form's Visible property from the main thread or a worker thread, simply call:
this.SetFormVisible(false);


There is an Microsoft Help article on this, but its unnecessarily hard to follow.

3 comments:

Dan said...

Hi Jeff,
I found your blog while looking for an updated version of sharepod because the one im using dies on certain files.

I decided to read through your blog and found your post about updating GUI elements from a worker thread. This can be a really annoying aspect of multi threaded development and I went through a similar thing myself a while back.

I posted some threads on my own blog detailing my experiences. I came up with 2 methods, one was a static class full of threadsafe methods for updating controls:

my first go - static class

The second (and better IMO) way of doing it was with anonymous methods and delegates, calling Invoke on the control to update then adding the code in an anonymous method, it cuts down on the amount of code you have to write considerably and hopefully will be useful to you.

better method - anonymous methods & delegates

Lemme know if you find this useful,
Best Regards
-Dan

http://www.danielbyrne.net

Rhelg said...

Hi Jeff

Just a quick note to say i have never seen this as eloquently put and easy to understand - as you said the MS help page is a little confusing so thanks for making my job a little easier :)

Unknown said...

Hi Jeff,

this is awesome simple 8^) thx for sharing with this.

Mikolaj