ContinueWith task throws cross-thread exception despite user interface context

I got the impression that using the Task ContinueWith method with a user interface context allows you to perform operations on user interface elements without throwing crossflows. However, I still get an exception when running the following code:

var context = TaskScheduler.FromCurrentSynchronizationContext(); Task<SomeResultClass>.Factory.StartNew(SomeWorkMethod).ContinueWith((t) => { myListControl.Add(t.Result); // <-- this causes an exception }, context); 

Any ideas?

+4
source share
2 answers

There are two different reasons for cross-thread exceptions.

The most common one is that you are trying to change the state of a control from a thread other than the UI. And that is not the problem you are pushing.

The one you come across is that elements must be created in the user interface thread . Your task is to create a control in another thread, and when you try to add this control to the controls created in the user interface thread, you get an exception.

You need to separate the work from creating the control in order to do this work. Try returning Func<Control> instead of Control and calling it in the user interface thread before adding it. Save most of the workflow on the task, but create a good closure by returning Func<> , which simply creates the control.

+7
source

Besides the reasons and possible solutions, Enigmativity said allready, you can always do something like this:

 var context = TaskScheduler.FromCurrentSynchronizationContext(); Task<SomeResultClass>.Factory.StartNew(SomeWorkMethod).ContinueWith((t) => { if (!myListControl.InvokeRequired) myListControl.Add(t.Result); // <-- this causes an exception else myListControl.Invoke((Action)(() => myListControl.Add(t.Result))); }, context); 

(assumed to be WinForms)

if you want mor control refactor to add to the method and use InvokeRequired inside the method to call itself inside Invoke if necessary:

 private void AddToListControl(MyItem item) { if (myListControl.InvokeRequired) { myListControl.Invoke((Action)(() => AddToListControl(item))); return; } myListControl.Add(item); } 

What Enigmativity hints is something like this:

 var result = Task<Action>.Factory.StartNew(SomeWorkMethod).ContinueWith((t) => { return () => myListControl.Add(t.Result); }); result.Result(); 

But IMHO is the same place that you got from the very beginning, because you need to call Result-Action in the right thread again.

+7
source

All Articles