一、目的:在开发过程中经常会遇到一个ListBox列表里面需要加载大量数据,但是加载过程中会假死卡顿影响用户体验,或者是你的主页面加载了大量控件,或者切换到一个有大量元素的页面都会有这种体验,因为加载的都是UI元素不能用多线程去处理,本文介绍一下应用BeginInvoke的方式加载的效果
二、实现
对于ListBox的加载大量数据
首先,想到的肯定是启用虚拟化,当然虚拟化是最佳选择,但有时布局或逻辑不允许应用VirtualizingStackPanel,或者是有些情况会破坏虚拟化。
其次,可以使用分页,将数据分成多页去展示(这种也是一种虚拟化)。
再者,就是应用尽量简单的元素去显示数据。
这里介绍的是BeginInvoke的方式,下面是不用虚拟化直接加载的效果
操作是生成10000个数据添加直接添加到ListBox的ItemsSource中,可以看到会卡住一段时间,如下是该功能代码
cs
var data = Enumerable.Range(0, 10 * 1000);
this.lb.ItemsSource = data;
下面使用BeginInvok优化一下执行的效果如下
可以看到窗口很快加载出来不会出现假死,数据会逐步加载进来,如下是该功能代码
cs
var data = Enumerable.Range(0, 10 * 1000);
ObservableCollection<int> beginInvokeDatas = new ObservableCollection<int>();
this.lb.ItemsSource = beginInvokeDatas;
foreach (var item in data)
{
this.Dispatcher.BeginInvoke(() =>
{
beginInvokeDatas.Insert(0, item);
}, DispatcherPriority.ApplicationIdle);
}
实现方式是先new一个ObservableCollection<int>赋值给ListBox的ItemsSource,之后通过Foreach循环中应用BeginInvoke的方式插入到列表,其中DispatcherPriority参数也有很多种,调试过程中找到适合的就好。
当然这种插入方式也有弊端,就是相比一次性加载的时间要久一些,这个时候就需要根据需求去取舍。
上面提到的其他情况卡页面或假死,又用不了多线程和虚拟化的情况也可以参考这种方式去加载元素。
三、环境
VS2022
四、示例
五、需要了解的知识点
DispatcherPriority Enum (System.Windows.Threading) | Microsoft Learn
Dispatcher Class (System.Windows.Threading) | Microsoft Learn
VirtualizingStackPanel 类 (System.Windows.Controls) | Microsoft Learn
六、源码地址
GitHub - HeBianGu/WPF-ControlDemo: 示例
GitHub - HeBianGu/WPF-ControlBase: Wpf封装的自定义控件资源库
GitHub - HeBianGu/WPF-Control: WPF轻量控件和皮肤库