Paul
Paul

Reputation: 1

C#: Listbox CrossThreading Issues

I am trying to access 3 listbox elements in my program from a different thread and keep getting the cross thread exceptions. I need a way to access my listboxes from another thread and have that code in a separate class called threadUtilities.cs. This way, all my thread access related code will be in a seperate class. Can anyone please provide generic code to access any listbox from another thread?

Upvotes: 0

Views: 847

Answers (2)

casperOne
casperOne

Reputation: 74560

You want to get the SynchronizationContext from the UI thread and then make it available to the background threads.

Depending on what technology you are using, a derived SynchronizationContext will be made available, but that's not of concern really; the Current property will return the one that is currently installed and both Windows Forms and WPF will install the proper one for you.

With the SynchronizationContext passed to the thread you want to make calls from, you can then call the Send method (analogous to the Invoke method) or the Post method (analogous to the BeginInvoke method) depending on your needs.

Here's an example:

public void Button1_OnClick(sender object, EventArgs e)
{
    // Get the current SynchronizationContext.
    // NOTE: Must make the call on the UI thread, NOT
    // the background thread to get the proper
    // context.
    SynchronizationContext context = SynchronizationContext.Current;

    // Start some work on a new Task (4.0)
    Task.Factory.StartNew(() => { 
        // Do some lengthy operation.
        ...

        // Notify the user.  Do not need to wait.
        context.Post(o => MessageBox.Show("Progress"));

        // Do some more stuff.
        ...

        // Wait on result.
        // Notify the user.
        context.Send(o => MessageBox.Show("Progress, waiting on OK"));
    });
}

Also, it should be mentioned that the BackgroundWorker class does all of this for you behind the scenes; if this model works for you over using the SynchronizationContext directly, then by all means, use that (the BackgroundWorker class uses SynchronizationContext internally).

Upvotes: 2

Sven
Sven

Reputation: 22703

Depends on whether it's WinForms or WPF. If WinForms, use the Control.Invoke method. If WPF, use the Dispatcher.

Simple WinForms sample:

ListBox listBox = GetListBoxFromSomewhere();
if( listBox.InvokeRequired )
    listBox.Invoke(() => listBox.Items.Add("Some item");
else
    listBox.Items.Add("Some item");

You could make a generic function for UI access like so:

void PerformUIOperation(Control c, Action action)
{
    if( c.InvokeRequired )
        c.Invoke(action);
    else
        action();
}

Use like this:

PerformUIOperation(listBox, () => listBox.Items.Add("Some item");

Upvotes: 1

Related Questions