- 我在 BackgroundWorker 的 DoWork 中循环创建 ViewModel 对象
- 我在每次迭代中报告进度,将新对象作为参数传递给 ProgressChanged 处理程序(它是 UI 线程的朋友)检索
- 在该处理程序中,对象被添加到绑定了 ListBox 的 ObservableCollection。
MY 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,检查我们的列表是否为空,如果不是,再次 RunWorkerAsync。