I'm getting a Cross-thread operation not valid
error with a project I am working on.
Class MyObject
{
public delegate void MessageHandler(object sender, EventArgs e);
public event MessageHandler OnConnect;
public void Process()
{
await Connection();//Line highlighted when exception is raised.
}
private async Task Connection()
{
await 'blocking task here'
OnConnect(this, new EventArgs());
}
}
//Windows form
MyObject o = new MyObject();
o.OnConnect += o_OnConnect;
Thread connectionThread = new Thread(o.Process);
connectionThread.Start();
void o_OnConnect(object snder, EventArgs e)
{
listBox.items.add("Connection");
}
Is the basic overview. Note that the thread process here does other work than connecting, it's also handling some other business and needs to stay alive.
Everything goes ok, I initiate the connection on the background and I get the thread error when trying to add the listbox item.
Can anyone shed some light on this for me? The handler is on the form thread, where I can add/remove items from this box at will.
I've also changed the thread call line to
o.Process();
To remove the thread piece, but I get the exact same error.
I'm not sure if I'm missing something obvious or I'm way out in the weeds here. I really just want this thread to run some async code, and throw events back into where it was called from for processing.
答案 0 :(得分:1)
Can anyone shed some light on this for me? The handler is on the form thread, where I can add/remove items from this box at will.
No, the handler is not on the "form thread". The form belongs to the UI thread, and the handler is run from your own connection thread. The event handler code is on the form object, but it is run on the connection thread.
The best solution is to not use cross-thread events at all. Personally, I would use Reactive Extensions instead.
However, if you're not willing to learn Reactive Extensions, you can use SynchronizationContext
or a TaskScheduler
to raise the handlers in the UI thread:
//Windows form
var ui = SynchronizationContext.Current;
MyObject o = new MyObject();
o.OnConnect += (sender, args) => ui.Post(_ => o_OnConnect(sender, args), null);
Thread connectionThread = new Thread(o.Process);
connectionThread.Start();
Note that new Thread
means you already have legacy code. There is almost certainly a better solution.
答案 1 :(得分:0)
You can't access UI elements from other threads. You need to do all UI access on the main GUI thread. Only do the long running tasks themselves as async, then do the GUI work after the await.
答案 2 :(得分:0)
The event from "MyObject" is being fired on another thread, you'll need to synchronize with the GUI thread in order to manipulate the control. The code below should help you out with this.
void o_OnConnect(object snder, EventArgs e)
{
if( listBox.InvokeRequired )
{
listBox.BeginInvoke( ( MethodInvoker )delegate ( )
{
listBox.items.add("Connection");
} );
}
else
{
listBox.items.add("Connection");
}
}