- 异步操作执行的过程中,如果需要展示操作的进度,可以考虑使用
IProgress<T>
和Progress<T>
。
static async Task CallMyMethodAsync()
{
var progress = new Progress<double>();
progress.ProgressChanged += (sender, args) =>
{
Console.WriteLine($"当前进度:{args}%");
};
await MyMethodAsync(progress);
}
static async Task MyMethodAsync(IProgress<double> progress = null)
{
double percentComplete = 0;
while (percentComplete < 100)
{
await Task.Delay(100);
percentComplete++;
if (progress != null)
progress.Report(percentComplete);
}
}
按照惯例,如果不需要报告进度,IProgress<T>
参数可以是 null,因此在 async 方法中一定要对此进行检查。
需要注意的是,IProgress<T>.Report
方法可以是异步的。这意味着真正报告进度之前,MyMethodAsync 方法会继续运行。
基于这个原因,最好把 T 定义为一个不可变类型,或者至少是值类型。如果 T 是一个可变的引用类型,就必须在每次调用 IProgress<T>.Report
时,创建一个单独的副本。
Progress<T>
会在创建时捕获当前上下文,并且在这个上下文中调用回调函数。这意味着,如果在 UI 线程中创建了 Progress<T>
,就能在 Progress<T>
的回调函数中更新 UI,
即使异步方法是在后台线程中调用 Report 的。