使用ICollectionView过滤ObservableCollection

3

我有一个绑定到 dataGridObservableCollection,现在我想要过滤我所看到的呈现数据,我发现我需要使用 ICollectionView,但我不确定如何在我的 MVVM 模式中添加 ICollectionView

我的简化代码如下:

public class MainViewModel : ViewModelBase , IBarcodeHandler
{
    public ObservableCollection<TraceDataItem> TraceItemCollectionViewSource { get; set; }
}

我的XAML
    <Window xmlns:controls="clr-namespace:Mentor.Valor.vManage.RepairStation.Controls"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            <DataGrid Grid.Row="2" ColumnWidth="*"  ItemsSource="{Binding TraceItemCollectionViewSource , Mode=TwoWay , UpdateSourceTrigger=PropertyChanged}" RowStyle="{StaticResource TraceRowStyle}"  IsReadOnly="True" Name="TraceDataGrid" Margin="5,5,5,5" Padding="5,5,5,5" AutoGenerateColumns="False">
    </Window>

我该如何在这里添加 ICollectionView 以便对视图应用过滤?
3个回答

6
你需要做的是:
public class MainViewModel : ViewModelBase, IBarcodeHandler
{
    public ICollectionView TraceItemCollectionView
    {
        get { return CollectionViewSource.GetDefaultView(TraceItemCollectionViewSource); }
    }

    public ObservableCollection<TraceDataItem> TraceItemCollectionViewSource { get; set; }
}

然后,在代码的某个地方(可能在构造函数中),添加您的过滤器:

TraceItemCollectionView.Filter = o =>
{
    var item = (TraceDataItem) o;

    //based on item, return true if it should be visible, or false if not

    return true;
};

在XAML中,您需要将绑定更改为TraceItemCollectionView属性。


那么,每次我更改TraceItemCollectionViewSource时,我需要在TraceItemCollectionView上调用RaisePropertyChanged来通知UI吗? - Night Walker
@NightWalker 是的,你需要。然而,ObservableCollection 的整个意义在于你不需要改变它。 - Andrei Tătar
4
如果使用集合的默认视图,就不需要改变 xaml 绑定。直接绑定到集合与绑定到默认视图相同(当绑定到集合时,ItemsControl 总是绑定到默认视图)。 - Xavier
1
@Xavier 正确。我实际上是在考虑将 TraceItemCollectionViewSource 设为私有的只读字段,不再公开。 - Andrei Tătar
当从数据库刷新数据时,您将如何更新 get { return CollectionViewSource.GetDefaultView(TraceItemCollectionViewSource); } - Eduards

1
你可以从命令中调用Filter回调函数,并从CollectionViewSource公开View属性:
public class ViewModel: INotifyPropertyChanged
{
    private CollectionViewSource data = new CollectionViewSource();
    private ObservableCollection<Child> observableChilds = new ObservableCollection<Child>();

    public ViewModel()
    {
        var model = new Model();
        model.ChildList.Add(new Child { Name = "Child 1" });
        model.ChildList.Add(new Child { Name = "Child 2" });
        model.ChildList.Add(new Child { Name = "Child 3" });
        model.ChildList.Add(new Child { Name = "Child 4" });
        //Populate ObservableCollection
        model.ChildList.ToList().ForEach(child => observableChilds.Add(child));

        this.data.Source = observableChilds;
        ApplyFilterCommand = new DelegateCommand(OnApplyFilterCommand);
    }

    public ICollectionView ChildCollection
    {
        get { return data.View; }
    }

    public DelegateCommand ApplyFilterCommand { get; set; }

    private void OnApplyFilterCommand()
    {
        data.View.Filter = new Predicate<object>(x => ((Child)x).Name == "Child 1");
        OnPropertyChanged("ChildCollection");
    }
}

//Sample Model used
public class Model
{
    public Model() 
    {
        ChildList = new HashSet<Child>();
    }

    public ICollection<Child> ChildList { get; set; }
}

public class Child
{
    public string Name { get; set; }
}

//View
<ListBox ItemsSource="{Binding Path = ChildCollection}" >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Label Content="{Binding Name}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

<Button Command="{Binding ApplyFilterCommand}"/>

0

CollectionView 不一定是最好的解决方案。你也可以使用一些简单的 LinQ 来过滤你的集合。看看这个简单的例子:

public ObservableCollection<TraceDataItem> FilteredData
{
    get 
    {
        return new ObservableCollection<TraceDataItem>(YourUnfilteredCollection.Where(
            i => MeetsFilterRequirements(i))); 
    }
}

private bool MeetsFilterRequirements(TraceDataItem item)
{
    return item.SomeProperty == someValue || item is SomeType;
}

这种方法的美妙之处在于您可以添加一些复杂的过滤要求。需要注意的一点是:每当此方法中的任何属性更改时,您都需要调用NotifyPropertyChanged("FilteredData")以确保UI相应地更新。

这将导致编译时异常。"Where" 返回的是一个 IEnumerable 而不是一个集合。 - Andrei Tătar
4
我认为这次编辑不好。您最好返回一个IEnumerable。如果您每次都要新建对象,那么ObservableCollection的作用是什么呢? - paparazzo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接