【问题标题】:C# Progress method executes after the await returns在 await 返回后执行 C# Progress 方法
【发布时间】:2017-02-08 23:59:47
【问题描述】:

我第一次尝试异步等待,但在使用 Progress 时遇到了问题。我使用 await 调用我的异步方法并传入我的进度操作。我想要发生的事情是显示进度,当方法完成时显示我们“完成!”的消息。被展示。发生的情况是显示进度,“完成!”显示,然后是最后一条进度消息,这是输出示例: 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";
    }

【问题讨论】:

    标签: asynchronous iprogress


    【解决方案1】:

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

    在这种情况下,既然您使用的是IProgress&lt;T&gt;,那么您的JustDoItAsync 应该永远不需要直接访问用户界面。所以你应该可以在你的awaits 上使用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";
    }
    

    另一种选择是将标志嵌入到您的 IProgress&lt;T&gt; 实现中。

    【讨论】:

    • 谢谢斯蒂芬,做到了。我将 ConfigureAwait(false) 扩展添加到任务中,并将 JustDoItAsync 调用移动到不同的异步方法中,然后从 click 事件中调用新方法。这让我可以在文本框中添加“Done1”。
    猜你喜欢
    • 2016-12-12
    • 2011-09-07
    • 1970-01-01
    • 1970-01-01
    • 2019-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    相关资源
    最近更新 更多