外观
MVVM 中 ICollectionView 与 ObservableCollection
ObservableCollection
public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged负责数据本身的变化通知(增、删、改)
- 实现了
INotifyCollectionChanged和INotifyPropertyChanged。 - 当向其中 添加、删除或替换元素 时,会自动通知绑定的 UI 更新。
- 关注的是“数据内容”的变化。
- 是一个具体的集合实现(类似
List<T>的增强版)。
ICollectionView
是一个视图接口,包装已有的集合 比如ObservableCollection。不会修改原始集合,只是“怎么展示”的逻辑。
- 提供:
Filter(自定义筛选逻辑)SortDescriptions(排序规则)GroupDescriptions(分组)CurrentItem(当前选中项)
- WPF 控件(如
DataGrid)在绑定集合时,内部会自动创建一个默认的ICollectionView。
var source = new ObservableCollection<Person>();
// ... 添加数据
ICollectionView view = CollectionViewSource.GetDefaultView(source);
view.Filter = o => (o as Person)?.Age >= 18; // 只显示成年人
// 原始 source 未变,但 UI 只显示满足条件的项结合使用
// ViewModel
private ObservableCollection<Order> _allOrders = new();
public ICollectionView OrdersView { get; }
public MyViewModel()
{
// 加载所有订单(原始数据)
LoadOrders(); // 填充 _allOrders
// 创建视图
OrdersView = CollectionViewSource.GetDefaultView(_allOrders);
// 设置展示逻辑
OrdersView.Filter = FilterOrder;
}
private bool FilterOrder(object item) => (item as Order)?.Status == "Pending";一个很典型的场景,一个总的数据源,需要根据状态显示到不同的子页面上
ViewModelBase.cs
//总数据源
public class ScanViewModelBase : ViewModelBase
{
/// <summary>
/// 扫描数据服务(单例,用于共享玻片信息)
/// </summary>
protected readonly ScanDataService _ScanDataService;
/// <summary>
/// 信息集合(从共享服务获取,切换页面不会被重新初始化)
/// </summary>
public ObservableCollection<SlideInfo> SildeInfos => _ScanDataService.SildeInfos;
public ScanViewModelBase(IContainerProvider containerProvider) : base(containerProvider)
{
_ScanDataService = containerProvider.Resolve<ScanDataService>();
}
// 每个子类实现自己的过滤器
public virtual bool SlideFilter(object slides) => true;
private ICollectionView? _filteredView;
protected ICollectionView CreateFilteredView()
{
if (_filteredView != null) return _filteredView;
var view = new ListCollectionView(_ScanDataService.SildeInfos);
view.Filter = SlideFilter;
_filteredView = view;
return view;
}
}完成页面ViewModel.cs
//页面1:
<DataGrid ItemsSource="{Binding CompleSlideView}"> </DataGrid>
public class ScanCompletedViewModel : ScanViewModelBase
{
private ICollectionView? _allSlides;
public ICollectionView AllSlides => _allSlides ??= CreateFilteredView();
//获取所有的,不写条件
private ICollectionView CreateCompleSlideView()
{
var view = new ListCollectionView(SildeInfos); //不同页面需要实例新的对象
view.Filter = CompleSlideFilter;
return view;
}
}失败页面ViewModel.cs
//页面2:
<DataGrid ItemsSource="{Binding FailedSlides}"> </DataGrid>
public class ScanFailedViewModel : ScanViewModelBase
{
private ICollectionView? _failedSlides;
public ICollectionView FailedSlides => _failedSlides ??= CreateFilteredView();
public override bool SlideFilter(object slides) =>
slides is SlideInfo slide && slide.State == SlideState.ScanFailed;
}总结
| 特性 | ObservableCollection<T> | ICollectionView |
|---|---|---|
| 类型 | 具体集合类 | 接口(视图) |
| 职责 | 管理数据本身 | 管理数据展示方式 |
| 通知机制 | 自动通知增删改 | 不直接通知,但依赖底层集合的通知 |
| 支持筛选/排序 | ❌ | ✅ |
| 是否修改原始数据 | ✅(本身是数据源) | ❌(只提供视图) |
| 通常用在 | ViewModel 的数据字段 | ViewModel 的绑定属性(供 View 使用) |
