从任务中检索值时,如何更新父窗体上的 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()"调用完成。 所以我们陷入了僵局。解决这个问题的正确方法是什么?

从任务中检索值时,如何更新父窗体上的 GUI

您正在阻止 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