C# Progress 方法在 await returns 之后执行
C# Progress method executes after the await returns
我第一次尝试异步等待,运行我遇到了使用 Progress 的问题。我使用 await 调用我的异步方法并传入我的进度操作。我想要发生的是显示进度,并且当方法完成时显示消息说我们 "Done!"。发生的事情是显示进度,显示 "Done!" 然后是最后一条进度消息,这是输出示例:
1、
2,
完成!
3
似乎异步已返回并且 UI 上下文在最终 Progress 有机会 运行 之前执行。我可以通过添加处理程序来克服这个问题,但要正确地遵循模式。
public async void button1_Click(object sender, EventArgs e)
{
await JustDoItAsync(new Progress<int>(ProgressUpdate));
textBox1.Text += "\r\nDone!\r\n";
}
public async Task JustDoItAsync(IProgress<int> progress)
{
for (int i = 0; i < 3; i++)
{
await Task.Delay(500);
progress.Report(i + 1);
}
}
private void ProgressUpdate(int step)
{
textBox1.Text += step + "\r\n";
}
不幸的是,这种行为并不意外。进度更新是排队的,可以在工作完成后到达。另一方面,任务完成是同步的(假设兼容上下文)。
在这种情况下,由于您使用的是 IProgress<T>
,因此您的 JustDoItAsync
永远不需要直接访问 UI。因此,您应该能够在该方法中的 await
上使用 ConfigureAwait(false)
,这应该会处理好它。
或者,您可以保留 "flag",在任务完成时设置它,并在您的进度报告中检查它,但这会使代码相当笨拙:
public async void button1_Click(object sender, EventArgs e)
{
Action<int> progressUpdate = ProgressUpdate;
await JustDoItAsync(new Progress<int>(update => progressUpdate?.Invoke(update)));
progressUpdate = null;
textBox1.Text += "\r\nDone!\r\n";
}
另一种选择是在您的 IProgress<T>
实现中嵌入标志。
我第一次尝试异步等待,运行我遇到了使用 Progress 的问题。我使用 await 调用我的异步方法并传入我的进度操作。我想要发生的是显示进度,并且当方法完成时显示消息说我们 "Done!"。发生的事情是显示进度,显示 "Done!" 然后是最后一条进度消息,这是输出示例: 1、 2,
完成! 3
似乎异步已返回并且 UI 上下文在最终 Progress 有机会 运行 之前执行。我可以通过添加处理程序来克服这个问题,但要正确地遵循模式。
public async void button1_Click(object sender, EventArgs e)
{
await JustDoItAsync(new Progress<int>(ProgressUpdate));
textBox1.Text += "\r\nDone!\r\n";
}
public async Task JustDoItAsync(IProgress<int> progress)
{
for (int i = 0; i < 3; i++)
{
await Task.Delay(500);
progress.Report(i + 1);
}
}
private void ProgressUpdate(int step)
{
textBox1.Text += step + "\r\n";
}
不幸的是,这种行为并不意外。进度更新是排队的,可以在工作完成后到达。另一方面,任务完成是同步的(假设兼容上下文)。
在这种情况下,由于您使用的是 IProgress<T>
,因此您的 JustDoItAsync
永远不需要直接访问 UI。因此,您应该能够在该方法中的 await
上使用 ConfigureAwait(false)
,这应该会处理好它。
或者,您可以保留 "flag",在任务完成时设置它,并在您的进度报告中检查它,但这会使代码相当笨拙:
public async void button1_Click(object sender, EventArgs e)
{
Action<int> progressUpdate = ProgressUpdate;
await JustDoItAsync(new Progress<int>(update => progressUpdate?.Invoke(update)));
progressUpdate = null;
textBox1.Text += "\r\nDone!\r\n";
}
另一种选择是在您的 IProgress<T>
实现中嵌入标志。