使用ListCollectionView的DataGrid如何无内存泄漏实现全属性过滤?
解决方案
1. 实现全列过滤
避免用反射遍历属性(性能损耗极大),直接硬编码需过滤的字段,提前缓存搜索文本计算结果:
private void ApplyFilter(bool search_by_text) { try { if (search_by_text) { var searchText = Search_text?.Trim().ToUpperInvariant() ?? string.Empty; AllData.Filter = item => { if (item is not DataModel data) return false; // 硬编码所有需要过滤的字段,替换为你的DataModel实际属性 return data.NAME?.ToUpperInvariant().Contains(searchText) == true || data.Age?.ToString().Contains(searchText) == true || data.Address?.ToUpperInvariant().Contains(searchText) == true; }; } else { // 执行单列过滤逻辑 var targetName = Selected_Name; AllData.Filter = targetName == null ? null : item => item is DataModel data && data.NAME == targetName; } AllData.Refresh(); } catch (Exception ex) { // 异常处理逻辑 } }
关键优化点:
- 直接访问
DataModel属性,消除反射的循环开销; - 用
ToUpperInvariant()替代ToUpper(),适配多语言环境且性能更稳定; - 提前处理搜索文本,避免在过滤委托中重复计算。
2. 单列过滤提速方案
37000条数据过滤慢的核心原因:误用ObservableCollection的Filter属性(本身无此属性)、过滤委托内重复执行判断逻辑、未开启UI虚拟化。
优化后的单列过滤逻辑:
private void ApplyFilter(bool search_by_text) { try { if (!search_by_text) { var targetName = Selected_Name; // 提前判断是否需要过滤,减少委托内重复检查 AllData.Filter = targetName == null ? null : item => item is DataModel data && data.NAME == targetName; AllData.Refresh(); } // ... 全列过滤逻辑 } catch (Exception ex) { // 异常处理 } }
额外提速手段:
- 给
DataModel.NAME建立哈希集合(频繁按名称过滤时):
过滤时先判断哈希集合是否包含目标名称,再执行后续逻辑;private HashSet<string> _nameSet; // 在Get_Contracts方法末尾初始化 _nameSet = new HashSet<string>(Data.Select(d => d.NAME)); - 开启DataGrid虚拟化(XAML中配置):
避免一次性渲染所有行,大幅降低UI负载。<DataGrid VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"/>
3. 修复内存泄漏问题
内存泄漏根源:误用ObservableCollection的Filter属性、过滤委托捕获外部可变变量导致的闭包引用、频繁创建新集合未释放旧实例。
修复步骤与代码:
- 始终通过
ListCollectionView(即AllData)执行过滤,ObservableCollection本身无Filter属性; - 提前将外部变量赋值给局部变量,减少闭包对ViewModel的持有;
- 复用已有
ListCollectionView,仅更新Filter并调用Refresh(),避免频繁创建新集合; - 在ViewModel销毁时清理Filter引用。
private void ApplyFilter(bool search_by_text) { try { if (search_by_text) { var searchText = Search_text?.Trim().ToUpperInvariant() ?? string.Empty; AllData.Filter = item => { if (item is not DataModel data) return false; return data.NAME?.ToUpperInvariant().Contains(searchText) == true || data.Age?.ToString().Contains(searchText) == true || data.Address?.ToUpperInvariant().Contains(searchText) == true; }; } else { var targetName = Selected_Name; AllData.Filter = targetName == null ? null : item => item is DataModel data && data.NAME == targetName; } AllData.Refresh(); } catch (Exception ex) { // 异常处理 } } // ViewModel销毁时调用该方法 public void Cleanup() { AllData.Filter = null; Data.Clear(); _alldata = null; _data = null; }
内容的提问来源于stack exchange,提问作者Lucy82
相关产品推荐
相关产品推荐

