Метод C# Progress выполняется после возврата await
Я пытаюсь асинхронное ожидание в первый раз и сталкиваюсь с проблемой с использованием Progress. Я вызываю свой асинхронный метод, используя await и pass в моем прогрессе. Я хотел бы, чтобы прогресс отображался, и когда метод заканчивает сообщение, что мы "Готово!" отображается. Что происходит, это то, что прогресс отображается "Готово!" а затем отображается последнее сообщение о ходе выполнения, это пример вывода: 1, 2,
Готово! 3
Похоже, что асинхронность вернулась, и контекст пользовательского интерфейса выполняется до того, как у финального Прогресса была возможность запустить. Я могу преодолеть это, добавив обработчики, но следуя шаблону правильно.
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";
}
1 ответ
К сожалению, такое поведение не является неожиданным. Обновления прогресса ставятся в очередь и могут поступить после завершения работы. С другой стороны, завершение задачи является синхронным (при условии совместимых контекстов).
В этом случае, так как вы используете IProgress<T>
тогда ваш JustDoItAsync
никогда не должен получать прямой доступ к интерфейсу. Таким образом, вы должны быть в состоянии использовать ConfigureAwait(false)
на ваше await
в этом методе, и это должно позаботиться об этом.
В качестве альтернативы, вы можете оставить "флаг", установить его, когда задача будет выполнена, и проверить его в своем отчете о ходе выполнения, но это делает код довольно неловким:
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>
реализация.