DataGrid控件是一个列表控件, 可以进行过滤,排序等。本文主要针对DataGrid的过滤功能进行分析, 并提供优化方案。
1)DataGrid的过滤过程:
用户输入过滤条件
调用DataGrid的CollectionViewSource的View.Refresh()功能
DataGrid控件内部调用CollectionView的RefreshOverride方法
CollectionView会调用CollectionViewSource的Filter回调函数来过滤符合自定义过滤条件的数据
CollectionView调用内部的OnCollectionChanged和OnCurrentChanged分别更新界面上的数据和当前选中的Item
2)通过分析发现(10W条数据, 实时过滤时UI非常卡,导致用户输入过滤字符丢失),调用CollectionViewSource的View.Refresh()的性能损耗主要集中于:
CollectionViewSource.Filter注册的方法,以及OnCollectionChanged(每次更新都导致ItemContainerGenerator重新构造UI元素)
3)优化方向:
减少CollectionViewSource.Filter注册的方法的耗时(在实时过滤中每个条件的更改都会调用Refresh从而调用Filter方法)
减少OnCollectionChanged调用的次数。
4)具体优化措施:
实例化3个Timer, 分别用于获取过滤后的数组(调用Filter)、调用OnCollectionChanged、OnCurrentItemChanged。3个timer分别由前一个timer完成时启动, 形成一个顺序操作。每次调用Timer时,先停止后续Timer的执行, 这样保证在合理的时间间隔里只有一次Refresh完整完成。
5)实现:
下面代码重载了ObservableCollection, 然后创建自定义的ListCollectionview.使用时只要用
CustomCollection
声明列表数据,包装为CollectionViewSource, 绑定到DataGrid的ItemSource即可。
//声明数组数据
public CustomCollection<StudyInfoModel> StudyList
{
get { return studyList; }
}
//包装为CollectionView
<CollectionViewSource Source="{Binding StudyList}" x:Key="StudyListView">
<CollectionViewSource.SortDescriptions>
<ComponentModel:SortDescription PropertyName="DateTime" Direction="Descending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
//绑定到DataGrid
<DataGrid
ItemsSource
="{
Binding
Mode
=
OneWay
,
Source
={
StaticResource
StudyListView