【发布时间】:2018-05-08 09:57:24
【问题描述】:
我有一个包含 Button 和 RichTextBox 控件的 WinForms 应用程序。用户点击 Button 后,执行 IO 需求操作。为了防止 UI 线程阻塞,我实现了 async/await 模式。我还想将此操作的进度报告到 RichTextBox 中。简化的逻辑如下所示:
private async void LoadData_Click(Object sender, EventArgs e)
{
this.LoadDataBtn.Enabled = false;
IProgress<String> progressHandler = new Progress<String>(p => this.Log(p));
this.Log("Initiating work...");
List<Int32> result = await this.HeavyIO(new List<Int32> { 1, 2, 3 }, progressHandler);
this.Log("Done!");
this.LoadDataBtn.Enabled = true;
}
private async Task<List<Int32>> HeavyIO(List<Int32> ids, IProgress<String> progress)
{
List<Int32> result = new List<Int32>();
foreach (Int32 id in ids)
{
progress?.Report("Downloading data for " + id);
await Task.Delay(500); // Assume that data is downloaded from the web here.
progress?.Report("Data loaded successfully for " + id);
Int32 x = id + 1; // Assume some lightweight processing based on downloaded data.
progress?.Report("Processing succeeded for " + id);
result.Add(x);
}
return result;
}
private void Log(String message)
{
message += Environment.NewLine;
this.RichTextBox.AppendText(message);
Console.Write(message);
}
操作成功完成后,RichTextBox 包含以下文本:
Initiating work...
Downloading data for 1
Data loaded successfully for 1
Processing succeeded for 1
Downloading data for 2
Data loaded successfully for 2
Processing succeeded for 2
Downloading data for 3
Done!
Data loaded successfully for 3
Processing succeeded for 3
如您所见,第三个工作项的进度报告在 Done! 之后。
我的问题是,导致进度报告延迟的原因是什么?我怎样才能实现LoadData_Click 的流程只有在报告所有进度后才会继续?
【问题讨论】:
-
什么是
IProgress<String>&Progress?它们的来源在哪里?它们对您的问题似乎很重要。 -
它们是 async-await 框架的一部分,请参阅:docs.microsoft.com/en-us/dotnet/api/…
-
@Enigmativity 是标准类(位于“mscorlib”dll 中),从 .NET 4.5 开始
-
@Markkknk - 所以,在阅读了文档之后,谢谢,问题似乎是
progress?.Report(正在将p => this.Log(p)的执行推到SychronizationContext。这意味着它必须等到 UI 消息循环空闲后才能执行该代码。我建议您尝试删除progress调用并直接写入日志。我怀疑问题会消失。
标签: c# winforms asynchronous async-await