【发布时间】:2012-10-20 12:43:59
【问题描述】:
- 我正在 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 在这种情况下是否是一种常见的解决方法,以及人们在这种情况下采用的一般解决方案是什么:从一个没有任何反应迟钝的背景循环。 我也提出了一些想法,非常感谢您的 cmets。
我能想到的想法:
- 不要经常报告进度 - 将其限制为 10 次,或每 10 次 新项目。
- 不要循环执行。创建需要的项目列表 创建的。在 DoWork 主体中,将列表中的 ONE 项目出列, 实例化并返回 ViewModel 实例。在 RonWorker 完成时, 更新 UI,检查我们的列表是否为空,如果不是, 再次 RunWorkerAsync。
【问题讨论】:
-
尝试使用定时器组件代替 Threed.sleep
标签: c# wpf viewmodel backgroundworker observablecollection