当前位置: 首页 > news >正文

WPF中UI线程频繁操作造成卡顿的处理

问题描述

有些时候,在项目开发中可能需要在某一很短时间内频繁操作UI控件,如以循环方式中瞬间向UI界面上添加1000张图片。这个任务场景有2个特点:
(1)所完成的任务是耗时任务——要频繁读取图片和加载图片。
(2)加载图片是UI操作,无法在非UI线程中完成。

解决办法:

能否每加载一个图片更新一下UI界面?而不是1000张图片读取完毕后一次性附加到界面上显示。

预备知识:

(1)WPF中Invoke和BeginInvoke方法,参考链接:http://www.cnblogs.com/Z-King/archive/2011/11/03/2234337.html
(2)Dispatcher的认识,参考链接:http://blog.csdn.net/albert528108/article/details/51503955
(3)DispatcherPriority的认识,参考链接:https://msdn.microsoft.com/zh-cn/library/system.windows.threading.dispatcherpriority.aspx
(4)依赖属性、INotifyPropertyChanged、ObservableCollection相关知识。



作者:hhp895
链接:https://www.jianshu.com/p/1d19514bccea
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

分析:

(1)所有UI的操作必须在UI线程上进行,无法在子线程中进行。
(2)线程上的操作又由Dispatcher分为不同的优先级。如果不希望UI上出现卡顿的情况,就必须将UI线程的图片加载(render)操作的优先级别降到UI线程上输入(input)操作的优先级之下。也就是input操作优先于图片呈现,界面就不会出现卡死状态。
(3)所有操作必须异步进行,这样不会堵塞线程。为了不让1000张图片同时加载到界面上,这里逐步调用BeginInvoke方法,每一次只比上一次多加载一张图片。何时终止,采用递归方式反复调用直到读完图片为止。

做法一:

未逐步加载,一次加载图片的做法。代码:

private void Btn_Click(object sender, RoutedEventArgs e){strings = loadDir(@"G:\BaiduYunDownload\风景图片壁纸\风景图片壁纸100张");lb.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>{lb.ItemsSource = loadDir(@"G:\BaiduYunDownload\风景图片壁纸\风景图片壁纸100张");}));}

效果图如下:

所有图片明显一次性出现,按钮点击后直接卡住。等所有图片都出现后,按钮的卡住状态恢复正常。

做法二:

图片一张张逐步加载,每次多增加一张图片。代码:

 int i;List<String> strings;ObservableCollection<String> strs = new ObservableCollection<string>();private void Btn_Click(object sender, RoutedEventArgs e){strings = loadDir(@"G:\BaiduYunDownload\风景图片壁纸\风景图片壁纸100张");strs.Clear();i = 0;lb.ItemsSource = strs;lb.Dispatcher.BeginInvoke(DispatcherPriority.Background, new AddItemDelegate(addItem));}private delegate void AddItemDelegate();private void addItem(){if (i < strings.Count){strs.Add(strings[i++]);lb.Dispatcher.BeginInvoke(DispatcherPriority.Background,new AddItemDelegate(addItem));}}private List<String> loadDir(string dirpath){List<String> strs = new List<string>();if (Directory.Exists(dirpath)){foreach (var item in new DirectoryInfo(dirpath).GetFiles("*.jpg")){strs.Add(item.FullName);}}return strs;}

效果图如下:

图片逐步加载,每次比上次多增加一张。按钮点击后立即恢复原来状态,UI无卡顿。

做法三:

做法背景

为了避免窗口UI操作卡顿,在Windows Form开发年代,微软就提出一个解决方案,在处理UI刷新时,使用Application.DoEvents()立即更新界面。参考msdn链接https://msdn.microsoft.com/zh-cn/library/system.windows.forms.application.doevents.aspx。

预备知识

(1)在WPF中如何改造实现DoEvents()方法。动态绘制心电图,参考链接:https://social.msdn.microsoft.com/Forums/zh-CN/febcee07-dc8b-44b4-8c0a-246daffdbe2b/wpf-?forum=wpfzhchs
(2)网上早有大师对该种做法进行了深度分析——《从Dispatcher.PushFrame()说起》http://www.cnblogs.com/loveis715/archive/2012/01/11/2319976.html

分析

实际上都是通过DoEvents()方法立即实现UI的重绘,而不是等所有图片加载完毕一次性显示,那样UI界面就卡住了。
代码:

 int i;List<String> strings;ObservableCollection<String> strs = new ObservableCollection<string>();private void Btn_Click(object sender, RoutedEventArgs e){strings = loadDir(@"G:\BaiduYunDownload\风景图片壁纸\风景图片壁纸100张");strs.Clear();lb.ItemsSource = strs;for (int j = 0; j < strings.Count; j++){strs.Add(strings[j]);DoEvents();}}public void DoEvents(){DispatcherFrame frame = new DispatcherFrame();Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,new DispatcherOperationCallback(ExitFrames), frame);Dispatcher.PushFrame(frame);}public object ExitFrames(object f){((DispatcherFrame)f).Continue = false;return null;}

效果

效果与做法二一样。

http://www.dtcms.com/a/342050.html

相关文章:

  • Ingress控制器深度解析:Nginx与Traefik实战指南
  • 【DICOM HL7】DICOM hl7协议的哪个字段对应操作者,操作者ID?
  • C++析构函数
  • Linux下Docker版本升级保姆攻略
  • 结合 Flutter 和 Rust 的跨平台开发方案
  • 微软Auzre云的技术支持运营模式是什么
  • Flutter - UI布局
  • Android APP防止应用被动态调试
  • 大数据毕业设计选题推荐-基于大数据的北京气象站数据可视化分析系统-Hadoop-Spark-数据可视化-BigData
  • 浏览器【详解】页面加载过程(含页面加载时序图,页面加载性能优化方案)
  • 搭建我的世界mc服务器全流程——阿里云游戏攻略
  • 09_测试与性能优化
  • 新型犯罪浪潮下的法律迷局:网络、AI与跨境犯罪解析
  • 惯性导航中的IMU传感器是什么?
  • 第5.2节:awk变量的使用
  • 适配器模式 java demo
  • 电能质量监测装置 分布式光伏安全并网“准入证”
  • AI工作负载“加速跑”,高性能网络如何“护航”?
  • EfficientVMamba代码略讲
  • 档案宝系统功能:权限分级,保障档案安全
  • KingbaseES数据库增删改查操作分享
  • 项目集成 Chrono 时间轴
  • Pytest 插件怎么写:从0开发一个你自己的插件
  • SamOutVXP: 轻量级高效语言模型
  • 用nohup setsid绕过超时断连,稳定反弹Shell
  • Spring 循环依赖:从 “死锁” 到 “破局” 的完整解析
  • 在.NET 8 中使用中介模式优雅处理多版本 API 请求
  • 大数据毕业设计选题推荐-基于大数据的鲍鱼多重生理特征数据可视化分析系统-Spark-Hadoop-Bigdata
  • AUTOSAR自适应平台(AP)中元类(Metaclass)、建模(Modeling) 和 ARXML 这三者的核心关系与区别
  • 阿里云上部署nuxt开发的项目(SSG和SSR混合渲染)