如何将ObservableCollection绑定到两个按IsWhite筛选的DataGrid?
这问题我之前做WPF项目时也遇到过,最靠谱的方案是用CollectionViewSource来做过滤,既能自动响应原集合的增删,还能处理单个项属性变化的情况,下面给你详细说两种常用方式:
方法一:使用CollectionViewSource(推荐,支持自动更新)
这是WPF中处理集合过滤的标准方式,能完美适配ObservableCollection的动态变化,包括集合增删项、单个项属性修改的场景。
步骤1:确保类A实现INotifyPropertyChanged(关键)
如果你的isWhiteEnum属性会在运行时被修改,类A必须实现INotifyPropertyChanged接口,否则修改属性后过滤视图不会自动更新:
public enum IsWhite { True, False } public class A : INotifyPropertyChanged { private IsWhite _isWhiteEnum = IsWhite.False; public IsWhite isWhiteEnum { get => _isWhiteEnum; set { if (_isWhiteEnum != value) { _isWhiteEnum = value; OnPropertyChanged(nameof(isWhiteEnum)); } } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
步骤2:在ViewModel中创建过滤视图
在你的ViewModel(推荐MVVM模式,也可以用窗口后台代码)里,创建两个ICollectionView,分别过滤出对应枚举值的项:
public class YourViewModel : INotifyPropertyChanged { public ObservableCollection<A> ACollection { get; set; } = new ObservableCollection<A>(); // 绑定到第一个DataGrid:过滤isWhiteEnum为False的项 public ICollectionView FalseItemsView { get; } // 绑定到第二个DataGrid:过滤isWhiteEnum为True的项 public ICollectionView TrueItemsView { get; } public YourViewModel() { // 为False项创建视图并启用实时过滤 var falseCvs = new CollectionViewSource { Source = ACollection }; falseCvs.LiveFilteringProperties.Add(nameof(A.isWhiteEnum)); falseCvs.IsLiveFilteringRequested = true; falseCvs.View.Filter = item => ((A)item).isWhiteEnum == IsWhite.False; FalseItemsView = falseCvs.View; // 为True项创建视图并启用实时过滤 var trueCvs = new CollectionViewSource { Source = ACollection }; trueCvs.LiveFilteringProperties.Add(nameof(A.isWhiteEnum)); trueCvs.IsLiveFilteringRequested = true; trueCvs.View.Filter = item => ((A)item).isWhiteEnum == IsWhite.True; TrueItemsView = trueCvs.View; } // ViewModel的INotifyPropertyChanged实现(如果需要通知其他属性变化) public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
步骤3:XAML中绑定DataGrid
直接把两个DataGrid的ItemsSource绑定到对应的视图即可:
<!-- 绑定isWhiteEnum为False的项 --> <DataGrid ItemsSource="{Binding FalseItemsView}" /> <!-- 绑定isWhiteEnum为True的项 --> <DataGrid ItemsSource="{Binding TrueItemsView}" />
方法二:使用Linq查询(简单但不支持自动更新)
如果你的集合不会动态增删,且isWhiteEnum属性不会修改,也可以用Linq的Where方法直接过滤,但这种方式的缺点是原集合变化时,视图不会自动更新,需要手动触发刷新:
ViewModel中的代码:
public class YourViewModel : INotifyPropertyChanged { public ObservableCollection<A> ACollection { get; set; } = new ObservableCollection<A>(); // 注意:这里是IEnumerable<A>,不是ObservableCollection public IEnumerable<A> FalseItems => ACollection.Where(a => a.isWhiteEnum == IsWhite.False); public IEnumerable<A> TrueItems => ACollection.Where(a => a.isWhiteEnum == IsWhite.True); // 原集合变化后,手动调用此方法通知UI更新 public void RefreshFilteredItems() { OnPropertyChanged(nameof(FalseItems)); OnPropertyChanged(nameof(TrueItems)); } // INotifyPropertyChanged实现 public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
XAML绑定:
<DataGrid ItemsSource="{Binding FalseItems}" /> <DataGrid ItemsSource="{Binding TrueItems}" />
注意:每次
ACollection增删项或者isWhiteEnum修改后,都要调用RefreshFilteredItems()来通知UI更新,否则DataGrid不会显示最新的过滤结果。
关键提醒
- 如果需要动态响应集合增删和属性变化,一定要用方法一的CollectionViewSource+LiveFiltering,这是WPF的最佳实践。
- 类A必须实现
INotifyPropertyChanged,否则单个项的isWhiteEnum修改后,过滤视图不会自动更新。
内容的提问来源于stack exchange,提问作者sushi7777




