【问题标题】:BackgroundWorker doing UI updates from a loopBackgroundWorker 从循环中执行 UI 更新
【发布时间】: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。

我能想到的想法:

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

【问题讨论】:

  • 尝试使用定时器组件代替 Threed.sleep

标签: c# wpf viewmodel backgroundworker observablecollection


【解决方案1】:

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

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

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

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

2) 不要循环执行。

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

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

【讨论】:

  • 正是我所希望的那种答案。谢谢! :)
  • ...奇怪的是,通过 ReportProgress 传递 10 个项目的列表会显示与以前相同的症状(仅传递一个时)。我开始研究 3) 但我开始怀疑
  • 刚刚做了。没有多大帮助,等待前 20 个项目也需要大约 2-3 秒,这是我试图避免的。 :) 我的目标是看到项目一个接一个地无缝显示,无论是 20 个还是 500 个,而无需任何初始等待。
  • 我怀疑我现在面临的是,尽管我在后台创建 ViewModel 对象,但 WPF 每次收到新的 ViewModel 列表时都需要创建 10 (20, 30) 个显示元素BW。它在 UI 线程上创建它们。创建 20 个 UIElement 似乎不太可能是一件大事,但仍然......这可能是我所面临的吗?如果是这样,我想我已经完成了,因为我无能为力。
猜你喜欢
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多