我正在开发一个Winform应用程序.它Method由BackgroundWorker Thread 启动.对不起.我之前没有提到这一点.
private void Method()
{
tasks[i] = Task.Factory
.StartNew(() => fileProcessor.ProcessEachMachine(mdetail))
.ContinueWith(UpdateLabel, TaskContinuationOptions.OnlyOnRanToCompletion);
}
Run Code Online (Sandbox Code Playgroud)
我有一个长期运行的功能ProcessEachMachine.在延续函数中,UpdateLabel我想访问UIlabel并更新状态.
private void UpdateLabel()
{
progressLbl.Text = "updated";
}
Run Code Online (Sandbox Code Playgroud)
但标签没有得到更新.如何访问UILabel并更新它的文本.
您必须在ContinueWith 上设置TaskScheduler.FromCurrentSynchronizationContext,否则它将不会在UI上下文中运行.以下是对此次ContinueWith调用必须使用的覆盖的MSDN.
它应该看起来像这样:
.ContinueWith(UpdateLabel, null,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
Run Code Online (Sandbox Code Playgroud)
似乎没有任何事情发生,但TPL目前正在吞噬您的跨线程异常.如果您不打算检查每个结果或检查其异常,则应该使用UnobservedTaskException.否则,当发生垃圾收集时,会发生异常......这可能会导致难以调试的错误.
UPDATE
根据您关于正在设置并由Backgroundworker启动的主要任务的更新,我的主要问题是为什么这不能使用任务启动?事实上,如果没有更多Method,那么这实际上只是双重工作,可能会混淆其他开发人员.你已经异步启动了,所以为什么不在backgroundworker中做你的工作并使用一个OnComplete方法UpdateLabel(因为后台工作者已经知道了上下文).
主要问题仍然是相同的,所以如果您觉得必须使用TPL,这里有一些其他解决方案:
Invoke在UpdateLabel方法中返回主UI线程Wait返回原始任务,然后使用worker的oncomplete事件来更新标签.这是我将如何做到这一点(所有伪代码)
后台工人方法:
Method() called because of Background worker
private void Method()
{
fileProcessor.ProcessEachMachine(mdetail);
}
Wire up background worker's OnRunWorkerCompleted:
if(!e.Cancelled && !e.Error)
UpdateLabel();
Run Code Online (Sandbox Code Playgroud)
仅任务方法
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());
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4647 次 |
| 最近记录: |