从 Task.Continuewith 更新 UI 标签
本文关键字:UI 标签 更新 Continuewith Task | 更新日期: 2023-09-27 18:32:10
我正在开发一个Winform应用程序。Method
由后台工作线程启动。对不起。我之前没有提到这一点。
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 上下文中运行。下面是重写上的 MSDN,您必须使用该替代来调用以继续使用。
它最终应该看起来像这样:
.ContinueWith(UpdateLabel, null,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
看起来好像什么都没有发生,但 TPL 目前正在吞噬您的交叉线程异常。如果您不打算检查每个结果或检查其异常,则可能应该使用 UnobservedTaskException。否则,当发生垃圾回收时,将发生异常...这可能会产生难以调试的错误。
更新
根据您对正在设置并由后台工作者启动的主任务的更新,我的主要问题是为什么这无法使用任务启动?事实上,如果Method
中没有更多,那么这实际上只是双重工作,可能会使其他开发人员感到困惑。您已经异步启动了,那么为什么不直接在后台工作线程中完成工作并使用将UpdateLabel
的 OnComplete 方法(因为后台工作线程已经可以感知上下文)。
不过,主要问题仍然相同,因此,如果您觉得必须使用 TPL,这里有一些其他解决方案:
- 您可以在 UpdateLabel 方法中
Invoke
回到主 UI 线程 - 您可以将当前上下文传递到后台工作线程中并改用它
- 您可以
Wait
返回原始任务,然后使用工作人员的 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());