- 我正在 BackgroundWorker 的 DoWork 内循环创建 ViewModel 对象
- 我报告每次迭代的进度,将新对象作为参数传递以由 ProgressChanged 处理程序(它是 UI 线程的朋友)检索
- 在该处理程序中,对象被添加到 ObservableCollection 中,并绑定了 ListBox。
我的 ViewModel 类包含两个字符串属性(Filename 和 ThumbnailPath),其 DataTemplate 包含绑定到这些属性的 Label 和 Image。
void bw_DoWork (object sender, DoWorkEventArgs e) {
List<string> files = e.Argument as List<string>;
FileInfo fi; int percent;
for (int i = 0; i < files.Count; i++) {
FileViewModel newItem = new FileViewModel(files[i]);
fi = new FileInfo(files[i]);
percent = i / files.Count * 100;
bwImportBrowserItems.ReportProgress(percent, newItem);
}
}
void bw_ProgressChanged (object sender, ProgressChangedEventArgs e) {
this.observableCollection.Add(e.UserState as FileViewModel);
}
典型数量的项目 (30-50) 的典型行为:UI 冻结约 2-3 秒;显示大约一半的项目; UI 再次冻结的时间较短,然后添加其余部分。
现在我明白,从循环中调用 UI 更新并不是最好的主意 - 我认为调用如此频繁,UI 没有时间响应它们,这就是为什么我们看到 UI “成组”更新,留下它在此期间没有反应。
我尝试添加Thread.Sleep(500)
作为循环的最后一行。这帮助我说明一切都按其应有的方式进行,因为随着经济放缓,项目被一个接一个地很好地添加没有任何无反应。
所以我尝试了不同的睡眠值定居于Thread.Sleep(25)
.这并不理想,但完全可以接受,并且非常接近它应有的样子。
我想问 Thread.Sleep 是否是一种常见的解决方法在这种情况下,以及人们在这种情况下采用的一般解决方案是什么:从后台循环更新 UI 集合,而不会出现任何无响应。
我也提出了一些想法,非常感谢您的评论。
我能想到的想法:
- 不要经常报告进度 - 将其限制为 10 次,或每 10 次
新东西。
- 不要循环进行。创建需要的项目列表
创建的。在 DoWork 主体中,从列表中出列一项,
实例化并返回 ViewModel 实例。在 RonWorkerCompleted 上,
更新 UI,检查我们的列表是否为空,如果不是,
再次运行WorkerAsync。
如果 Thread.Sleep 是此类情况下的常见解决方法
将其视为最后的手段。您正在增加总处理时间(而不是 CPU 负载)。
1) 不要太频繁地报告进度 - 将其限制为 10 次,或每 10 个新项目。
这是基本的想法。收集新项目并通过 ReportProgess 发送列表。调整列表的大小。
2)不要循环执行。
可能,但每个 Bgw 的 1 项看起来要慢得多。它甚至可能表现出相同的症状。
3)通过ConcurrentQueue解耦。您可以让 DoWork 填充队列,而 Dispatcher.Timer 可以清空它。还尝试使用该计时器处理批次。您可以调整计时器的优先级和批量大小。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)