Reputation: 1
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
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
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