Pattern for Properly Updating a Control from Another Thread

If you've done any Windows programming with threads, you've probably run into the problem of modifing a control you've added to your Form from a thread you've started. The answer was to Marshal the data through a delegate from the Thread through the Invoke() method on the Form object (this.Invoke(delegate, object args[] )). This wasn't too bad, but I always found the code a bit messy and never really had a simple streamlined way of acomplishing this.

Yesterday I was doing something simple in a Form and VS.net 2005 was being, what seemed to me, extra picky about this. Aparently VS.net 2003 wasn't very strict and would let you get away with poorly threaded code.

Instead of punting and turning off the new cross threading checks (by setting CheckForIllegalCrossThreadCalls to false which is how VS.net 2003 functions), I did some reading. MS has a very simple slick pattern for handling both the Threaded call and the non-threaded call in one method.

In the following example, they demonstraite this pattern using a TextBox. The create a delegate and a method called SetText(string s) that you must always use when working with the textBox1 control:

public class Form1 : Form
{
private TextBox textBox1;
// ...
delegate void SetTextCallback(string text);

private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d
= new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
// ...
}


Notice how the SetText method adds itself as a delegate when an invoke is required. If an invoke is NOT required it just functions normally. Pretty cool, eh?

I was able to apply this pattern with accessing and modifling ListBox.Items colleciton as well and it worked flawlessly.

Here's the MS HOWTO article: How to: Make Thread-Safe Calls to Windows Forms Controls

kick it on DotNetKicks.com

4 comments: