【发布时间】:2017-07-18 02:14:50
【问题描述】:
我正在尝试在使用 async/await 调用运行操作后更新进度条,但在更新进度条时 UI 冻结。
基本上,当使用 BackgroundWorker 时,这是一个非常简单的要求,但现在使用此 async/await 调用似乎有点复杂。
首先,async/await 用法可以像 BackgroundWorker 那样填充进度条吗?这两种方法有什么共同点吗?
在我的 UI 上,我有一个进度条和一个按钮,当单击按钮时,进度条开始更新,但 UI 冻结,这不应该发生,因为 async/await 应该以“并发”方式工作。 如果我使用 BackgroundWorked 执行此操作,则 UI 不会冻结。
有人可以解释一下我做错了什么吗?我该如何修改下面的代码以在进度条更新时保持 UI 响应? 在更新进度条时,async/await 用法是否可以像 BackgroundWorker 那样表现?
下面是我的代码:
private async void button1_Click(object sender, EventArgs e)
{
await CallMethodAsync();
}
private async Task CallMethodAsync()
{
this.progressBar1.Value = 0;
this.progressBar1.Maximum = 1000000;
var progressbar1 = new Progress<double>();
progressbar1.ProgressChanged += Progressbar1_ProgressChanged;
await ExecuteMethodAsync(progressbar1);
}
private async Task ExecuteMethodAsync(IProgress<double> progress = null)
{
await Task.Run(new Action(() => {
double percentComplete = 0;
bool done = false;
while (!done)
{
if (progress != null)
{
progress.Report(percentComplete);
}
percentComplete += 1;
if (percentComplete == 1000000)
{
done = true;
}
}
}));
}
private void Progressbar1_ProgressChanged(object sender, double e)
{
this.progressBar1.Increment(1);
}
【问题讨论】:
-
不要等待更新栏的任务,使用
this.Invoke(new Action()....更新UI。 -
忽略@Crowcoder 的评论。你的代码很好。等待和使用
Progress<T>实际上是这种情况的现代成语。您的代码中的问题是您没有做任何 实际 工作。你只是用更新向 UI 线程发送垃圾邮件,它跟不上。例如,如果您将迭代计数更改为100而不是1000000,并在while循环中添加await Task.Delay(500);,您不仅可以摆脱await Task.Run()(即循环可以在您的ExecuteMethodAsync()方法中而不是 lambda 中),它将按您的意愿工作。
标签: c# .net asynchronous