Paul Liebrand's Weblog

Welcome to my blog mainly about SharePoint

Skip to: Content | Sidebar | Footer

Google Search

Simple Pattern / Solution for Cross-thread operation not valid

16 July, 2010 (10:54) | .NET | By: Liebrand

If you have ever done any threaded programming in .NET WinForms you have more than likely run into the following error message at some point:

Cross-thread operation not valid 

InvalidOperationException was unhandled

Cross-thread operation not valid: Control ‘’ accessed from a thread other than the thread it was created on.

This exception is normally displayed while running in DEBUG mode. In release mode, everything appears to run as expected but at some point you will definitely run into a thread deadlock issue.

The following code represents a pattern I would use to get around this problem and I insured all the calls that would touch the UI from a different thread followed it:

 
private void button2_Click(object sender, EventArgs e)
{

    ThreadPool.QueueUserWorkItem(notUsed =>
    {
        for (int i = 0; i < 100; i++)
        {
            UpdateStatus(string.Format("Loading record {0} of 100", i, 100));
        }
    });
}
       
private void UpdateStatus(string message)
{
    if (InvokeRequired)
    {

        BeginInvoke((MethodInvoker)delegate() { UpdateStatus(message); });
        return;
    }

    textBox1.Text = message;
}

Although this pattern works it is not as elegant and can be further refined and simplified. To accomplish this I created an extension method for the Form as such:

    public static class FormExtensions
    {
        public static void HandleCrossThreadUI(this Form form, MethodInvoker code)
        {
            if (form.InvokeRequired)
            {
                form.BeginInvoke(code);
                return;
            }

            code.Invoke();
        }
    }

By modifying the original code above to make use of the extension I can simply the code a little further:

private void button2_Click(object sender, EventArgs e)
{

    ThreadPool.QueueUserWorkItem(notUsed =>
    {
        for (int i = 0; i < 100; i++)
        {
            UpdateStatus(string.Format("Loading record {0} of 100", i, 100));
        }
    });
}
       
private void UpdateStatus(string message)
{
    this.HandleCrossThreadUI(() => { textBox1.Text = message; });
}

This may not look like much but when you start adding more and more code, it becomes a lot easier to read.

Hopefully you find this a little useful.


Post to Twitter Post to Delicious Post to Digg Post to Facebook Post to Reddit