几年前,您必须创建一个 BackgroundWorker 对象来完成这项工作以保持您的 UI 响应。
几年前我们就有了 async-await 可以完成这项工作。 async-await 函数看起来像同步代码,但每当它看到 await 时,代码就会停止,直到它等待的任务完成。同时,等待的线程有时间做其他事情,比如更新进度条,或保持 UI 响应。一旦线程等待的任务完成,线程将继续执行等待之后的语句。
要使用 async-await,您唯一要做的就是声明您的事件处理程序异步。完成后,您可以调用其他异步函数并等待它们的结果。
在您开始您的流程后,您可以等待 Task.Delay(TimeSpan)。在这个方法中,主线程没有做任何事情,所以它有时间做其他 UI 工作。延迟结束后,可以更新进度条,查看进程是否结束。
using System.Diagnostics;
private async void pictureBox1_Click(object sender, EventArgs e)
{
// start the progress, don't wait until finished yet:
var process1 = Process.Start("c:/installer.exe").WaitForExit();
while (!process1.HasExited)
{
// process not finished yet, increase progress bar and wait a while
this.progressBar1.Step();
await Task.Delay(TimeSpan.FromSeconds(0.2);
}
// if here, process1 has finished: we are halfway:
progressBar1.Value = (progressbar1.Minimum + progressBar1.Maximum)/2;
// start process 2
var process2 = Process.Start("c:/installer2.exe");
while (!process2.HasExited)
{
// process not finished yet, increase progress bar and wait a while
this.progressBar1.Step();
await Task.Delay(TimeSpan.FromSeconds(0.2);
}
// both processes finished; full progressbar:
this.progressBar1.Value = this.progressBar1.Maximum;
}
当然,您可能会遇到安装需要很长时间的问题。如果值变得太高,请考虑不再更新进度条
var halfWay = (progressbar1.Minimum + progressBar1.Maximum)/2;
while (!process1.HasExited)
{
if (this.progressBar1.Value < halfWay)
this.progressBar1.Step();
...
}
请注意,异步等待是由一个线程完成的。它不是多任务处理。 Eric Lippert 对 stackoverflow 有一个很好的类比:
async/await - Is this understanding correct?
假设你必须做早餐。烤一些面包,煮一些鸡蛋。
- 同步:开始烤面包。等到烘烤结束。开始煮鸡蛋,等鸡蛋煮熟。
- 异步但非并发:开始烤面包,烤面包时开始煮鸡蛋。在煮鸡蛋的同时,您还可以做其他事情,例如泡茶。过了一会儿,你等到鸡蛋煮熟,然后等到面包烤好。这通常是异步等待。
- 异步和并发:雇一个厨师烤面包,雇一个厨师煮鸡蛋,等到两个厨师都吃完。在这里,烘烤和烹饪是由不同的线程完成的。这是最昂贵的方法