尽管UI上下文,任务ContinueWith导致跨线程异常

Amb*_*ite 4 c# multithreading task

我的印象是使用Task的ContinueWith方法和UI上下文允许对UI元素执行操作而不会导致跨线程异常.但是,在运行以下代码时,我仍然遇到异常:

var context = TaskScheduler.FromCurrentSynchronizationContext();

Task<SomeResultClass>.Factory.StartNew(SomeWorkMethod).ContinueWith((t) =>
   {
      myListControl.Add(t.Result); // <-- this causes an exception
   }, context);
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Eni*_*ity 7

跨线程异常有两种不同的原因.

最常见的是您尝试从非UI线程修改控件的状态.这不是你要打的问题.

你要击中的是必须在UI线程上创建控件.您的任务是在不同的线程上创建控件,当您尝试将此控件添加到在UI线程上创建的控件时,您将获得异常.

您需要将工作与控件创建分开才能使其工作.尝试返回a Func<Control>而不是a,Control并在添加它之前在UI线程上调用它.将大部分工作保留在任务线程上,但通过返回Func<>仅执行控件创建来形成一个很好的紧密闭包.


Car*_*ten 7

除了原因和可能的解决方案,Enigmativity告诉所有你已经可以做到这样的事情:

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);
Run Code Online (Sandbox Code Playgroud)

(假设这是WinForms)

如果你想要mor控件重构添加到方法中并使用方法内部的InvokeRequired在Invoke中调用自己,如果需要:

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

   myListControl.Add(item);
}
Run Code Online (Sandbox Code Playgroud)

暗示的暗示是这样的:

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

result.Result();
Run Code Online (Sandbox Code Playgroud)

但恕我直言,这是你从一开始就得到的同一个地方,因为你必须再次在正确的线程上调用Result-Action.