Asynchronous C#Progress方法在等待返回后执行

Asynchronous C#Progress方法在等待返回后执行,asynchronous,iprogress,Asynchronous,Iprogress,我第一次尝试async Wait,但在使用Progress时遇到了问题。我在progress操作中使用wait和pass调用异步方法。我希望看到的是,将显示进度,当方法完成时,将显示消息说我们“完成了!”。此时会显示进度,“完成!”然后显示最后一条进度消息,这是一个输出示例: 1. 二, 完成了! 三, 似乎在最终进度有机会运行之前,异步已返回,UI上下文已执行。我可以通过添加处理程序来克服这一问题,但必须正确地遵循该模式 public async void button1_Click(obj

我第一次尝试async Wait,但在使用Progress时遇到了问题。我在progress操作中使用wait和pass调用异步方法。我希望看到的是,将显示进度,当方法完成时,将显示消息说我们“完成了!”。此时会显示进度,“完成!”然后显示最后一条进度消息,这是一个输出示例: 1. 二,

完成了! 三,

似乎在最终进度有机会运行之前,异步已返回,UI上下文已执行。我可以通过添加处理程序来克服这一问题,但必须正确地遵循该模式

 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";
    }
public async void按钮1\u单击(对象发送方,事件参数e)
{
等待JustDoItAsync(新进展(ProgressUpdate));
textBox1.Text+=“\r\n完成!\r\n”;
}
公共异步任务JustDoItAsync(IProgress进程)
{
对于(int i=0;i<3;i++)
{
等待任务。延迟(500);
进度报告(i+1);
}
}
私有void ProgressUpdate(int-step)
{
textBox1.Text+=步骤+“\r\n”;
}

不幸的是,这种行为并非意外。进度更新已排队,并且可以在工作完成后到达。另一方面,任务完成是同步的(假设上下文兼容)

在这种情况下,由于您使用的是
IProgress
,因此您的
JustDoItAsync
不需要直接访问UI。因此,您应该能够在该方法中的
await
s上使用
ConfigureAwait(false)
,这应该会解决问题

或者,您可以保留一个“标志”,在任务完成时设置它,并在进度报告中检查它,但这会使代码变得相当笨拙:

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";
}
public async void按钮1\u单击(对象发送方,事件参数e)
{
动作progressUpdate=progressUpdate;
等待JustDoItAsync(新进度(更新=>progressUpdate?.Invoke(更新));
progressUpdate=null;
textBox1.Text+=“\r\n完成!\r\n”;
}

另一种选择是将标志嵌入到您的
IProgress
实现中。

谢谢Stephen,这样做了。我将ConfigureAwait(false)扩展添加到任务中,并将JustDoItAsync调用移动到另一个异步方法中,然后从click事件调用新方法。这允许我在文本框中添加“Done1”。