c# - 调用方法包含UI交互时如何等待所有任务?
问题描述
首先,我知道有WaitAll
和非阻塞WhenAll
. 我目前的问题略有不同,但希望我可以使用其中一种方法。
所以,我有一个从外部 WebApi 加载一个大而复杂的对象的表单。加载以块的形式完成,如下所示:
public void LoadObject()
{
LoadChunk1();
LoadChunk2();
LoadChunk3();
LoadChunk4();
LoadChunk5();
}
public async void LoadChunk1()
{
//Clear controls, data bindings etc...
await Task.Run(() =>
{
chunk = someService.LoadChunk1();
});
//Update controls, data bindings etc...
}
这同样适用于所有方法。这一切都很好。现在我需要在主加载方法中添加一个进度条,以便用户知道何时加载了所有内容。此外,这些方法可能经常从表单中的其他位置调用,而不一定是从 main 方法调用。
同步加载不是一个选项,因为 UI 会阻塞几秒钟,所以一切都必须保持原样。
有没有办法WhenAll
在任务数组上使用?或者在这种情况下是不可能的,因为我访问了 UI?如果我使用BeginInvoke
怎么办?
解决方案
我解决这个问题的方法是让任何报告进度的方法都采用 Progress 对象。这些对象可以包含 a:计数器(双精度)或 b:进度对象列表。这允许该方法要么只是增加计数器,要么将对象分成几个并将每个子进度分配给不同的方法。进度对象将具有计算整个树的总进度的方法。
所以你的例子看起来像这样:
public void LoadObject(Progress progress)
{
var subProgress = progress.Split(5)
LoadChunk1(subProgress[0] );
LoadChunk2(subProgress[1]);
LoadChunk3(subProgress[2]);
LoadChunk4(subProgress[3]);
LoadChunk5(subProgress[4]);
}
public async void LoadChunk1(Progress progress)
{
await Task.Run(() =>
{
chunk = someService.LoadChunk1();
progress.Value = 1; // This chunk is complete
});
}
将其与在主线程上运行的单独轮询器相结合,每 0.2 秒左右检查一次整体进度,并更新进度条。这允许以任何顺序进行处理,并且您可以从任何线程报告进度。
如果您有一个模态进度对话框,您可以使用它WhenAll
来生成一个在加载所有块时完成的任务,并在任务完成时关闭对话框。
推荐阅读
- airflow - 在 Airflow 中调度 dag 运行
- visual-studio-2017 - IIS Express 配置错误“注册 URL 失败”
- unit-testing - 以特定顺序列出 DLL 时单元测试失败,但仅在 32 位编译中
- python - Python Selenium 在单击而不是选项卡时打开一个新窗口
- mysql - 如何在 vb.net 中使用 allowUserToAddRows = false 填充(通过代码)datagridview(未绑定)
- floating-point - Fortran 中的正/负无穷大常数
- android - Firebase 身份验证中的“使用 Google 登录”不起作用
- r - 在一个图中 R 中的 2 个两个矩阵的逐行(并排)箱线图?
- mysql - 用于合并同一行的两个查询的sql查询
- git - Jenkins 共享库 - 访问 Git 变更集相关信息