你必须在ContinueWith上设置TaskScheduler.FromCurrentSynchronizationContext,否则它将不会在UI上下文中运行。这是MSDN关于你必须使用的ContinueWith调用的重写方法。
最终应该看起来像这样:
.ContinueWith(UpdateLabel, null,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
虽然看起来什么也没有发生,但TPL当前正在吞噬您的跨线程异常。如果您不打算检查每个结果或检查其异常,则应该使用
UnobservedTaskException。否则,在进行垃圾回收时,异常将在那时发生……这可能会导致难以调试的错误。
更新
根据您有关主任务由Backgroundworker设置和启动的更新,我的主要问题是为什么不能使用任务来启动?实际上,如果
Method
中没有更多内容,那么这只是重复劳动,可能会混淆其他开发人员。您已经异步启动了,那么为什么不在后台工作器中完成工作,并使用一个
OnComplete方法来
UpdateLabel
(因为后台工作器已经具有上下文感知)。
但主要问题仍然存在,因此如果您必须使用TPL,则以下是一些其他解决方案:
- 您可以在UpdateLabel方法中使用
Invoke
返回到主UI线程。
- 您可以将当前上下文传递到后台工作器中,并使用该上下文。
- 您可以
Wait
等待原始任务返回,然后使用工作程序的oncomplete事件更新标签。
以下是我会如何做(所有伪代码)
Background Worker Method:
Method() called because of Background worker
private void Method()
{
fileProcessor.ProcessEachMachine(mdetail);
}
Wire up background worker's OnRunWorkerCompleted:
if(!e.Cancelled && !e.Error)
UpdateLabel();
仅限任务方法
Call Method() from the main thread and just let the TPL do its work :)
Task.Factory.StartNew(() => fileProcessor.ProcessEachMachine(mdetail))
.ContinueWith((precedingTask)=>{if(!precedingTask.Error)UpdateLabel;},
null, TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
ProcessEachMachine
在更新标签之前已经完成了吗?也许这个任务正在运行很长时间,非常长的时间。 - GETah