【WPF】从普通 ItemsControl 到支持筛选的 ItemsControl:深入掌握 CollectionViewSource 用法

✨ 从普通 ItemsControl 到支持筛选的 ItemsControl:深入掌握 CollectionViewSource 用法

在日常 WPF 开发中,我们经常需要对数据进行筛选、排序、分组等操作,而原生的 ItemsControl 并不直接支持这些功能。本文将介绍如何通过 CollectionViewSource 给一个普通的 ItemsControl 加上 动态筛选功能 ,并指出其中的一些关键注意点


📦 一、初始结构:普通 ItemsControl 显示列表

我们从一个最简单的 ItemsControl 开始:

xml 复制代码
<ItemsControl ItemsSource="{Binding MBConfigList}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding FileName}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

这个控件可以显示绑定的 MBConfigList 数据,但没有任何过滤能力。


🛠️ 二、目标:支持按光源类型筛选

我们希望最终能够让用户勾选光源类型,动态筛选出指定类型的数据。例如:

  • 支持"全选"
  • 多个 CheckBox 动态刷新列表
  • 用户操作后立即生效

🧰 三、改造步骤


1️⃣ 引入 CollectionViewSource

我们在 ViewModel 中定义一个 CollectionViewSource 并设置过滤事件:

csharp 复制代码
private CollectionViewSource _viewSource;

public ICollectionView FilteredMBConfigList
{
    get => _viewSource?.View;
    private set => SetProperty(ref _filteredView, value); // 实现 INotifyPropertyChanged
}

public void InitializeFilteredView()
{
    _viewSource = new CollectionViewSource
    {
        Source = GlobalData.Instance.saveInfo.MBConfigList
    };
    _viewSource.Filter += ApplyFilter;
    FilteredMBConfigList = _viewSource.View;
}

FilteredMBConfigList 必须是支持通知的不然界面是不会变化的。


2️⃣ 编写筛选逻辑 ApplyFilter

csharp 复制代码
private void ApplyFilter(object sender, FilterEventArgs e)
{
    if (e.Item is MBConfigInfo item)
    {
        var selectedTypes = LightSourceItems
            .Where(x => x.IsChecked)
            .Select(x => x.Name)
            .ToHashSet();//ToHashSet()是为了更快的查询

        // 显示所有或匹配项
        e.Accepted = selectedTypes.Count == 0 || selectedTypes.Contains(item.LightSourceType);
    }
}

private CollectionViewSource _viewSource; 不能申明成局部变量,不然ApplyFilter只能生效一次。

e.Accepted == true 的选项才会被显示出来。


3️⃣ UI 绑定到新集合

xml 复制代码
<ItemsControl ItemsSource="{Binding FilteredMBConfigList}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding FileName}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

这样,控件就用上了支持筛选的视图。


🚨 四、关键注意事项


⚠️ 1. CollectionViewSource 必须缓存

不能每次 get 都创建新的 CollectionViewSource,否则不会触发 .Refresh()

csharp 复制代码
// 错误写法(每次都 new):
public ICollectionView Filtered => new CollectionViewSource { Source = xxx }.View;

// 正确:只创建一次

⚠️ 2. 调用 View.Refresh() 以应用筛选

数据变化时,你必须手动调用:

csharp 复制代码
FilteredMBConfigList.Refresh();

建议绑定项(如 CheckBox)中 PropertyChanged 事件或命令中执行刷新。

FilteredMBConfigList.Refresh();调用后会重新触发ApplyFilter 以到达筛选的目的。


⚠️ 3. 筛选逻辑不要复杂耗时

FilterEventArgs 的处理函数会在每次刷新时对 所有项 执行。避免长计算!


⚠️ 4. UI 绑定的是 View,不是 CollectionViewSource 本身

绑定语法是:

xml 复制代码
ItemsSource="{Binding FilteredMBConfigList}"

不是 _viewSource,而是其 .View


✅ 五、示例:支持多选筛选项结构

使用一个简单的模型:

csharp 复制代码
public class LightSourceFilterItem : INotifyPropertyChanged
{
    public string Name { get; }
    public bool IsChecked { get; set; } // 实现通知
}

ViewModel:

csharp 复制代码
public ObservableCollection<LightSourceFilterItem> LightSourceItems { get; set; }

LightSourceItems = new ObservableCollection<LightSourceFilterItem>(
    new[] { "上光源", "下光源", "侧光源" }.Select(name =>
    {
        var item = new LightSourceFilterItem(name) { IsChecked = true };
        item.PropertyChanged += (_, __) => FilteredMBConfigList?.Refresh();
        return item;
    }));

XAML:

xml 复制代码
<ItemsControl ItemsSource="{Binding LightSourceItems}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

🏁 六、总结

优点 ✅ 注意点 ⚠️
支持筛选、排序、分组 .Refresh() 要手动调用
ItemsControl, ListBox, DataGrid 搭配无缝 Filter 逻辑要快
不改变原始集合 不要频繁 new CollectionViewSource

使用 CollectionViewSource 是 WPF 中实现数据视图分离的经典方式,非常适合构建支持过滤的 UI。

相关推荐
DreamLife☼8 小时前
复杂Agent系统架构设计
系统架构·wpf·agent·组件·设计·构架·说明
SamChan9013 小时前
PDF翻译服务端到端基准测试:4款主流方案的吞吐量、延迟、内存占用对比
服务器·网络·python·ai·pdf·wpf
bugcome_com14 小时前
Avalonia 控件模板实战:从 WPF 迁移自定义 Button 样式的完整指南
wpf
七夜zippoe14 小时前
DolphinDB 故障排查实战:系统、数据库与集群常见问题诊断
数据库·wpf·集群·常见问题·故障排查·dolphindb
dalong102 天前
WPF:箭头绘制程序
wpf·自定义绘制
张工在路上2 天前
WPF 布局基础概述
大数据·hadoop·wpf
迪飞特科技4 天前
分布式事务下 Spring 声明式事务失效的 3 种修复方案
分布式·spring·wpf
2601_962174176 天前
Redis 简介
数据库·redis·wpf
SamChan907 天前
Python+PyMuPDF提取PDF表格并翻译:表格结构检测与双语重建实战
windows·python·ai·pdf·wpf
SamChan908 天前
Python+OpenCV检测PDF翻译后排版偏移:像素级格式一致性验证
python·opencv·ai·pdf·wpf