Task ContinueWith导致跨线程异常,尽管UI上下文
本文关键字:尽管 UI 上下文 异常 线程 ContinueWith Task | 更新日期: 2023-09-27 18:07:31
我的印象是使用带有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();