2011-09-06 40 views
4

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

var context = TaskScheduler.FromCurrentSynchronizationContext(); 

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

任何想法?

+0

任何你不使用'Invoke'来访问UI控件的原因? – Yahia

+0

你是从调度员的线程开始执行任务吗?如果不是这样可以解释它。 – BrokenGlass

回答

7

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

最常见的一种情况是您尝试从非UI线程修改控件的状态。这是而不是您遇到的问题。

你打的那个是控件必须在UI线程上创建。你的任务是在不同的线程上创建控件,当你试图将这个控件添加到在UI线程上创建的控件时,你会得到异常。

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

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)

如果你想铁道部控制重构的加入到一个方法:

+0

感谢您的回复。你非常正确 - 我的SomeWorkMethod创建了一个用户控件,它创建了自己的控件。尽管这应该在同一个UI线程上完成(如果不使用任务,这不会导致异常),但在ContinueWith操作中使用此用户控件时,它会导致异常。我的最终解决方案是在StartNew方法中使用UI上下文,以及ContinueWith方法,然后运行。 – Amberite

+0

实际上,在思考了这一点之后,在StartNew方法中创建的用户控件将处于单独的线程中 - 我完全错过了这个,这是愚蠢的。无论如何,所有已解决:) – Amberite

7
从原因和可能的解决方案Enigmativity告诉媒体链接,你可以八方通做这样的事情

除了并使用InvokeRequired方法中调用自身的调用里面,如果需要:

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

    myListControl.Add(item); 
} 

什么Enigmativity在暗示是someth荷兰国际集团这样的:

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

result.Result(); 

但恕我直言,这只是你从一开始就得到了,因为你必须再次调用结果,操作正确的线程在同一个地方。

+0

只是我看到'.InvokeRequired'作为“代码味道”?即您需要一次作为快速修复,现在可以随处使用。 – adrianm

+0

我真的不知道 - 这只是一个小小的害虫,如果你对UI编写代码,你一定要意识到 - 我倾向于在ViewModels中重构它,所以现在对我来说几乎是很自然的。 – Carsten

+0

感谢您的精心制作!Enigmativity非常正确,因为有一些控件是创建的,应该在同一个UI线程中创建,但出于某种原因,在使用任务时不会。我提高了你的寿命,因为这在其他情况下是有用的信息。 – Amberite