从任务更新UI标签。继续
问题描述:
我正在使用Winform应用程序。 Method
由一个BackgroundWorker线程启动。对不起。我之前没有提到这一点。从任务更新UI标签。继续
private void Method()
{
tasks[i] = Task.Factory
.StartNew(() => fileProcessor.ProcessEachMachine(mdetail))
.ContinueWith(UpdateLabel, TaskContinuationOptions.OnlyOnRanToCompletion);
}
我有一个长时间的运行功能ProcessEachMachine
。在继续功能UpdateLabel
我想访问UIlabel并更新状态。
private void UpdateLabel()
{
progressLbl.Text = "updated";
}
但标签没有更新。如何访问UILabel并更新它的文本。
答
您必须在ContinueWith上设置TaskScheduler.FromCurrentSynchronizationContext,否则它将不会在UI上下文中运行。 Here is the MSDN on the override that you must use for this call to ContinueWith。
它应该结束这样看:
.ContinueWith(UpdateLabel, null,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
它可能看起来像什么也没发生,但TPL正在吞噬你的跨线程异常。如果您不打算检查每个结果或检查其异常,则应该使用UnobservedTaskException。否则,当发生垃圾收集时,会发生异常,然后......可能很难调试错误。
更新基于你的主要任务是建立更新
,并通过一个BackgroundWorker开始,我的主要问题是,为什么这不能用一个任务开始?事实上,如果Method
中没有更多,那么这真的只是双重工作,可能会混淆其他开发人员。你已经异步启动了,为什么不在背景工作中做你的工作,并使用UpdateLabel
(作为后台工作人员已经了解情境)的方法。
的主要问题仍然是,虽然是相同的,所以这里有一些其他的解决方案,如果你觉得你必须使用TPL:
- 您可以
Invoke
返回到主UI线程UpdateLabel方法中 - 您可以将当前上下文传递到后台工作,然后使用它替换
- 您可以
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();
任务唯一方法
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 2012-04-23 18:11:06
ContinueWith是什么保证?假设我错了吗? – Sandeep 2012-04-23 18:12:22
@Sandeep不,你没有错。你只需要确保你回到UI线程。 – Servy 2012-04-23 18:19:41