1

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.

Bmo
  • 1,212
  • 11
  • 34
  • [How to update the GUI from another thread in C#?](http://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c) – Reza Aghaei Oct 20 '16 at 18:40
  • https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx | you could use invoke to update GUI – Timon Post Oct 20 '16 at 18:42
  • I know this is only a example, but `public void Process()` really should be `public Task Process()`. you should not be doing `async void` unless you are writing a event handler. – Scott Chamberlain Oct 20 '16 at 19:44

3 Answers3

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.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Mr. Cleary, as always thank you for the information. I've used your blog on TCP operations (for this project coincidentally) as well. I had put ReactiveX on my list of things to do when I had some time. I guess I was just trying to cobble something together quickly and have the approach all wrong to begin with. I'll probably use `SynchronizationContext` to get the project moving again. – Bmo Oct 21 '16 at 15:20
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.

SledgeHammer
  • 7,338
  • 6
  • 41
  • 86
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");           
        }
}
WBuck
  • 5,162
  • 2
  • 25
  • 36