wpf 使用 ICollectionView 过滤 ObservableCollection

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30916475/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:12:52  来源:igfitidea点击:

Filtering ObservableCollection with ICollectionView

c#wpfxamlmvvmdata-binding

提问by Night Walker

I have ObservableCollectionbinded to dataGridand now I want to filter the presented data I see that I need to use ICollectionViewbut I am not sure how to add ICollectionViewwith my MVVMpattern.

我已经ObservableCollection绑定dataGrid,现在我想过滤我看到需要使用的呈现数据,ICollectionView但我不确定如何添加ICollectionView我的MVVM模式。

My code simplified looks following:

我的代码简化如下:

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

My XAML

我的 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>

How I can add ICollectionViewhere in order to apply filtering to the view?

我如何ICollectionView在此处添加以对视图应用过滤?

回答by Andrei T?tar

You would need to:

你需要:

public class MainViewModel : ViewModelBase, IBarcodeHandler
{
    public ICollectionView TraceItemCollectionView
    {
        get { return CollectionViewSource.GetDefaultView(TraceItemCollectionViewSource); }
    }

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

then, somewhere in the code (maybe in the constructor) add your filter:

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

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

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

    return true;
};

And, in XAML, you would need to change the binding to TraceItemCollectionView property.

而且,在 XAML 中,您需要更改对 TraceItemCollectionView 属性的绑定。

回答by Sheridan

A CollectionViewis not always the best solution. you can also filter your collection using some simple LinQ. Take this simple example:

ACollectionView并不总是最好的解决方案。您还可以使用一些简单的 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;
}

The beauty of this method is that you can add some complex filtering requirements. One thing to note: whenever any properties in this method are changed, you'd need to call NotifyPropertyChanged("FilteredData")to ensure that the UI will be updated accordingly.

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

回答by E-Bat

You may invoke the Filter callback from a Command and expose the View property from CollectionViewSource :

您可以从 Command 调用 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}"/>