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



我的印象是使用带有UI上下文的Task的ContinueWith方法允许在UI元素上执行操作而不会引起跨线程异常。然而,当运行以下代码时,我仍然得到一个异常:

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

任何想法?

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

最常见的一种是尝试从非ui线程修改控件的状态。这是,而不是

你碰到的是控件必须在UI线程上创建。你的任务是在另一个线程上创建控件,当你试图将此控件添加到UI线程上创建的控件时,你会得到异常。

您需要将工作从控件创建中分离出来以使其工作。尝试返回Func<Control>而不是Control,并在添加它之前在UI线程上调用它。保持任务线程上的大部分工作,但通过返回Func<>,只是做控件创建形成一个很好的紧闭。

除了原因和可能的解决方案之外,Enigmativity告诉allready你总是可以这样做:

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);

(假设这是WinForms)

如果你想要更多的控制,将add重构到一个方法中,并在方法中使用invokerrequirequired,以便在需要时在Invoke中调用自己:

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

Enigmativity所暗示的是这样的:

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

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

相关内容

最新更新