Передача информации о ходе выполнения операции
Задача: отреагировать на прогресс выполнения операции.
Решение:
Используйте
IProgress<T> и Progress<T>. Ваш асинхронный метод должен получать аргумент IProgress<T>; здесь T — тип прогресса, о котором вы хотите сообщать:async Task MyMethodAsync(IProgress<double> progress = null)Пример использования в вызывающем коде:
{
bool done = false;
double completed = 0;
while (!done) {
...
progress?.Report(completed);
}
}
async Task CallMyMethodAsync()По действующим соглашениям параметр
{
var progress = new Progress<double>(
p => progressBar.Value = p
);
await MyMethodAsync(progress);
}
IProgress<T> может быть равен null, если вызывающей стороне не нужны уведомления о прогрессе. Включите соответствующую проверку в асинхронный метод.Лучше определить
T как неизменяемый тип (или тип-значение). Если T является изменяемым ссылочным типом, то вам придётся самостоятельно создавать отдельную копию при каждом вызове IProgress<T>.Report.Progress<T> сохраняет текущий контекст при создании и активизирует свой обратный вызов в этом контексте. Это означает, что если Progress<T> конструируется в UI-потоке (как в методе CallMyMethodAsync выше), то вы сможете обновить пользовательский интерфейс из его обратного вызова, даже если асинхронный метод вызывает Report из фонового потока.Заметьте, что, если метод поддерживает уведомления о прогрессе, лучше, чтоб он также поддерживал отмену.
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 2.