1
  • 我在 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 集合而完全没有任何无响应。我也提出了一些想法,非常感谢您的意见。

我能想到的想法:

  1. 不要经常报告进度 - 将其限制为 10 次,或每 10 个新项目。
  2. 不要循环执行。创建需要创建的项目列表。在 DoWork 主体中,从列表中取出一个项目,实例化并返回 ViewModel 实例。在 RonWorkerCompleted 上,更新 UI,检查我们的列表是否为空,如果不是,再次 RunWorkerAsync。
4

1 回答 1

1

如果 Thread.Sleep 是此类情况下的常见解决方法

将其视为最后的手段。您正在增加总处理时间(不是 CPU 负载)。

1) 不要经常报告进度——将其限制为 10 次,或每 10 个新项目。

这就是基本思想。通过 ReportProgess 收集新项目并发送列表。调整列表的大小。

2)不要循环执行。

可能,但是您的每个 Bgw 的 1 项看起来要慢得多。它甚至可能表现出相同的症状。

3) 通过 ConcurrentQueue 解耦。您可以让 DoWork 填充一个队列,而 Dispatcher.Timer 可以清空它。还尝试使用该计时器处理批次。您可以调整计时器的优先级和批量大小。

于 2012-10-20T12:51:59.880 回答