Subscribe to Blog.Parse(typeof(PsychoCoder), Richard McCutchen);        RSS Feed
-----

Handling the dreaded cross-thread Exception

Icon Leave Comment
Many times when working with Threading (whether it be a Thread, BackgroundWorker or any other kind of threading) you may run into the dreaded cross-thread exception. That is because you cannot access your GUI controls from a different thread without using one of many methods. In this posting we'll be taking a look at a couple different ways of avoiding this, in both C# and VB.NET.

The first way, which is the way I use most often, is to create an extension method to handle the invoke of my GUI controls.

In VB.NET you must create a Module for this, and we must add the Extension Attribute to the procedure. For this to work in VB.NET you need to import the following Namespaces



This will give us access to what we need to pull this off. So first let's take a look at our VB.NET module

Imports System.ComponentModel
Imports System.Runtime.CompilerServices

Public Module MyInvoke
    <Extension()> _
    Public Sub CustomInvoke(Of T As ISynchronizeInvoke)(ByVal control As T, ByVal toPerform As Action(Of T))
        If control.InvokeRequired Then
            control.Invoke(toPerform, New Object() {control})
        Else
            toPerform(control)
        End If
    End Sub
End Module



But how do I use this you may ask. Well that's easy as it will now appear in the IntelliSense of any control that has the Invoke method, in this example we'll show how to use it in a Label control. It will be used like this

Label1.CustomInvoke(l => l.Text = "Hello World!")



Now if you do that in a threaded situation you will not have a cross-thread exception.

Now let's take a look at this in C#. In C# you still need the System.ComponentModel Namespace but we dont need the System.Runtime.CompilerServices Namespace. Also this can be a class (not Module like in VB.NET) and it must be marked with the static keyword (the method itself must be marked static as well). Now let's take a look at our C# version

using System;
using System.ComponentModel;

namespace PsychoCoder.Examples
{
    public static class MyInvoke
    {
        public static void CustomInvoke<T>(this T @control, Action<T> toPerform) where T : ISynchronizeInvoke
        {
            if (@control.InvokeRequired)
                @control.Invoke(toPerform, new object[] { @control });
            else
                toPerform(@control);
        }
    }
}




And believe it or not we would use it the same exact way we would in VB.NET:

Label1.CustomInvoke(l => l.Text = "Hello World!");



Another way of avoiding the cross-thread exception is to use a Delegate. So now let's look at how we can do this using a delegate in VB.NET. This example will be pretty generic and used for any control. First our Delegate declaration

'Our delegate method
Delegate Sub ChangeTextDelegate(ByVal ctrl As Control, ByVal str As String)



Now our method to use our Delegate
'The method with the delegate signature
Private Sub ChangeText(ByVal ctrl As Control,  ByVal str As String) 
  If ctrl.InvokeRequired Then 
    ctrl.Invoke(New ChangeTextDelegate(AddressOf ChangeText),  New Object() { ctrl, str })
    Return
  End If
  ctrl.Text = str
End Sub



Then we can use it in our project like so

ChangeText(Label1, "Hello World!")



If used in a threaded environment we can now update the text of Label1 from a thread other than the main UI thread without getting the cross-thread exception.

This can also be done in C# as well, so let's take a look at how tis would be done with C#. First the delegate signature

//Our delegate method
private delegate void ChangeTextDelegate(Control ctrl, string text);



Then our method to use our newly declared delegate

//The method with the delegate signature
private static void ChangeText(Control ctrl, string str)
{
	if (ctrl.InvokeRequired) 
        {
		ctrl.Invoke(new ChangeTextDelegate(ChangeText), new object[] { ctrl, str });
	}
	ctrl.Text = str;
}



Then we would call it the same way we would in VB.NET

ChangeText Label1, "Hello World!");



You now the two most common ways you can avoid the dreaded cross-thread exceptions when working in a multi-threaded environment, and they say that Knowing is half the battle. Use this information to make your life easier and go forth and become a threading ninja. Thanks for reading :)

0 Comments On This Entry

 

Trackbacks for this entry [ Trackback URL ]

There are no Trackbacks for this entry

July 2020

S M T W T F S
   1234
5678 9 1011
12131415161718
19202122232425
262728293031 

Recent Entries

Search My Blog

1 user(s) viewing

1 Guests
0 member(s)
0 anonymous member(s)