You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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中配置):
    <DataGrid VirtualizingStackPanel.IsVirtualizing="True"
              VirtualizingStackPanel.VirtualizationMode="Recycling"/>
    
    避免一次性渲染所有行,大幅降低UI负载。

3. 修复内存泄漏问题

内存泄漏根源:误用ObservableCollection的Filter属性、过滤委托捕获外部可变变量导致的闭包引用、频繁创建新集合未释放旧实例。

修复步骤与代码:

  1. 始终通过ListCollectionView(即AllData)执行过滤,ObservableCollection本身无Filter属性;
  2. 提前将外部变量赋值给局部变量,减少闭包对ViewModel的持有;
  3. 复用已有ListCollectionView,仅更新Filter并调用Refresh(),避免频繁创建新集合;
  4. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 21:02:49