BackgroundWorker从循环执行UI更新 [英] BackgroundWorker doing UI updates from a loop

查看:90
本文介绍了BackgroundWorker从循环执行UI更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  • 我正在BackgroundWorker的DoWork内部的循环中创建ViewModel对象
  • 我正在报告每次迭代的进度,并将新对象作为参数传递给ProgressChanged处理程序(与UI线程成为朋友)
  • 在该处理程序中,将对象添加到绑定了ListBox的ObservableCollection.

MY ViewModel类包含两个字符串属性(文件名和ThumbnailPath),其DataTemplate包含绑定到这些属性的Label和Image.

MY ViewModel class contains two string properties (Filename and ThumbnailPath), and its DataTemplate contains a Label and an Image, bound to these properties.

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再次冻结了较短的时间,其余的被添加了.

Typical behavior for a typical number of items (30-50): UI freezes for about 2-3 seconds; around a half of the items is displayed; UI freezes again for a shorter time and the rest is added.

现在,我知道从循环中调用UI更新不是最好的主意-我认为调用如此频繁,导致UI没有时间响应它们,这就是为什么我们看到UI成组"更新的原因,与此同时使其无响应.

Now I understand it's not the best idea to call UI updates from a loop - I figured the calls come so frequently the UI doesn't have time to respond to them, that's why we see the UI being updated "in groups", leaving it unresponsive in the meantime.

我尝试将 Thread.Sleep(500)添加到循环的最后一行.这有助于我说明一切正常,因为速度变慢了,一项又一项地添加,而没有任何反应.

I tried adding Thread.Sleep(500) as the last line of the loop. This helped me illustrate that everything works as it should, because with this slowdown, the items were being added nicely one after another without any nonresponsiveness.

所以我尝试了不同的睡眠值,并 Thread.Sleep(25)设置了.

So I tried different sleep values and settled for Thread.Sleep(25). This is not ideal but quite acceptable and comes pretty close to what it should look like.

我想问一下在这种情况下Thread.Sleep是否是一种常见的解决方法,以及人们在这种情况下可以采用的一般解决方案:从以下位置更新UI集合完全没有任何响应的后台循环.我也想出了一些主意,感谢您的评论.

I'd like to ask if the Thread.Sleep is a common workaround in situations like these, and also what is the general solution people go with in this situation: to update an UI collection from a background loop without ANY unresponsiveness at all. I've also come up with some ideas and I'd appreciate your comments.

我能想到的想法:

  1. 不要如此频繁地执行ReportProgress-将其限制为10次或每10次新项目.
  2. 请勿循环执行.创建需要创建.在DoWork正文中,从列表中取出一个项目,实例化并返回ViewModel实例.在RonWorkerCompleted上,更新用户界面,检查我们的列表是否为空,如果不是,再次运行RunWorkerAsync.

推荐答案

如果在这种情况下Thread.Sleep是常见的解决方法

if the Thread.Sleep is a common workaround in situations like these

考虑不得已.您正在增加总处理时间(而不是CPU负载).

Consider it a last resort. You are increasing the total processing time (not CPU load).

1)不要如此频繁地报告进度-将其限制为10次或每10个新项.

1) Don't ReportProgress so often - limit it to 10 times, or to every 10 new items.

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

That is the basic idea. Collect new Items and dispatch a List through ReportProgess. Tune the size of the list.

2)不要循环执行.

2) Don't do it in a loop.

可能,但是您每Bgw的1项看上去要慢得多.它甚至可能显示相同的症状.

Possible, but your 1-item per Bgw looks a lot slower. It might even show the same symptoms.

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

3) Decouple through a ConcurrentQueue. You can let DoWork fill a Queue and a Dispatcher.Timer could empty it. Also try to process batches with that timer. You can tune the priority of the timer and the batch size.

这篇关于BackgroundWorker从循环执行UI更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆