从任务中检索值时,如何更新父窗体上的 GUI
本文关键字:更新 窗体 GUI 何更新 检索 任务 | 更新日期: 2023-09-27 18:33:33
我想我在这里缺少一些明显的东西,但是在使用任务和检索值时如何更新 GUI?(我正在尝试使用 await/async 而不是 BackgroundWorker)
在我的控件上,用户单击了一个按钮,该按钮将执行需要时间的操作。 我想提醒父窗体,以便它可以显示一些进度:
private void ButtonClicked()
{
var task = Task<bool>.Factory.StartNew(() =>
{
WorkStarted(this, new EventArgs());
Thread.Sleep(5000);
WorkComplete(this, null);
return true;
});
if (task.Result) MessageBox.Show("Success!");//this line causes app to block
}
在我的父窗体中,我正在收听 WorkStarted 和 WorkComplete 以更新状态栏:
myControl.WorkStarting += (o, args) =>
{
Invoke((MethodInvoker) delegate
{
toolStripProgressBar1.Visible = true;
toolStripStatusLabel1.Text = "Busy";
});
};
如果我错了,请纠正我,但应用程序挂起,因为"调用"正在等待 GUI 线程可用,直到我的"ButtonClicked()"调用完成。 所以我们陷入了僵局。解决这个问题的正确方法是什么?
您正在阻止 UI 线程 Task.Result 阻止,直到任务完成。
试试这个。
private async void ButtonClicked()
{
var task = Task<bool>.Factory.StartNew(() =>
{
WorkStarted(this, new EventArgs());
Thread.Sleep(5000);
WorkComplete(this, null);
return true;
});
await task;//Wait Asynchronously
if (task.Result) MessageBox.Show("Success!");//this line causes app to block
}
可以使用
Task.Run
在后台线程上执行代码。基于任务的异步模式指定进度更新的模式,如下所示:
private async void ButtonClicked()
{
var progress = new Progress<int>(update =>
{
// Apply "update" to the UI
});
var result = await Task.Run(() => DoWork(progress));
if (result) MessageBox.Show("Success!");
}
private static bool DoWork(IProgress<int> progress)
{
for (int i = 0; i != 5; ++i)
{
if (progress != null)
progress.Report(i);
Thread.Sleep(1000);
}
return true;
}
如果面向 .NET 4.0,则可以使用 Microsoft.Bcl.Async
;在这种情况下,必须使用 TaskEx.Run
而不是 Task.Run
。我在我的博客上解释了为什么你不应该使用Task.Factory.StartNew
。