Skip to main content
 首页 » 编程设计

c#之Collection View : Filter does not work when binding to e. g。列表框

2024年06月03日6www_RR

我有一些包含笔记的级联容器,其中有一个包含所有笔记的主容器。笔记容器是在树状层次结构中制作的,树结构越深,层次结构就越具体。我只有一个列表的原因与非常复杂的数据管理有关,这不是问题的一部分。

主笔记容器有一个ObservableCollection,所有子笔记容器都通过CollectionView绑定(bind)到ObservableCollection。子笔记容器有一个过滤器可以过滤掉他们的笔记。在常规代码中,一切正常, View 始终显示元素,但是当我将它们绑定(bind)到 e. G。 ListBox,元素未被过滤,主列表中的所有元素均未过滤显示。我当然知道有一个 ListCollectionView,但由于 CollectionView 来自 IEnumerable,我很好奇 ListBox 是如何访问主列表的,如果它不从 CollectionView 访问 SourceCollection

换句话说,我不太清楚为什么我需要 ListCollectionView 来实现 ColletionView 应该适合的非常基本的行为。在我看来,ListCollectionView 是强制性的,而不是其他 View 真的适合 ListBox

这是一个小例子

XAML:

<Window x:Class="ListCollection.MainWindow" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Title="MainWindow" Height="350" Width="525"> 
    <StackPanel Orientation="Horizontal"> 
        <ListBox Width="100" ItemsSource="{Binding Model}"></ListBox> 
        <ListBox Width="100" ItemsSource="{Binding View1}"></ListBox> 
        <ListBox Width="100" ItemsSource="{Binding View2}"></ListBox> 
    </StackPanel> 
</Window> 

C#:

using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Windows; 
using System.Windows.Data; 
 
namespace ListCollection 
{ 
    /// <summary> 
    /// Interaktionslogik für MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
        public ObservableCollection<int> Model 
        { 
            get; private set; 
        } 
 
        public ICollectionView View1 
        { 
            get; private set; 
        } 
 
        public ICollectionView View2 
        { 
            get; private set; 
        } 
 
        public MainWindow() 
        { 
            InitializeComponent(); 
 
            DataContext = this; 
 
            Model = new ObservableCollection<int>(); 
            View1 = new CollectionView(Model); 
            View1.Filter = (o) => 
            { 
                return ((int)o) > 50; 
            }; 
 
            View2 = new CollectionView(View1); 
            View2.Filter = (o) => 
            { 
                return ((int)o) > 70; 
            }; 
 
            for (int i = 0; i < 100; i++) 
                Model.Add(i); 
        } 
    } 
} 

谢谢 马丁

请您参考如下方法:

CollectionView class 文档备注部分的第一行说:

You should not create objects of this class in your code.

所以,我猜它可能不是按照您的使用方式设计的。

我总是使用 CollectionViewSource.GetDefaultView(collection) (最终会为 ListCollectionView 返回一个 ObservableCollection<T>,但它返回为一个 ICollectionView)。


编辑:为了澄清一些事情,这里有一些关于 Collection View 的附加信息。

Data Binding Overview 上有一个相当不错的 Collection View 概述。文档页面,这是一个很好的阅读。它解释了为什么每个集合有一个默认 View 。每当将集合用作数据绑定(bind)的源时,它就会由框架创建。 GetDefaultView 方法获取该 View (如果它不存在则创建它)。对该方法的后续调用将始终返回相同的 View 。

如果你绑定(bind)一个 ItemsControl.ItemsSource直接到一个集合,它将使用默认 View 。因此,绑定(bind)到默认 View 和绑定(bind)到集合本身具有相同的结果。如果您希望将多个 View 放入同一个集合中,那么您将需要创建自己的 Collection View 并显式绑定(bind)到这些 View ,而不是绑定(bind)到集合或默认 View 。

有几种创建 Collection View 的方法,具体取决于您是从代码还是 xaml 创建它们。

从 Viewmodel 代码创建

创建一个新的 ListCollectionView ,将集合传递给构造函数。如果您在 View 模型代码中,则可以将 View 公开为属性(通常类型为 ICollectionView )。

查看模型代码:

private ObservableCollection<Item> mItems; 
public ICollectionView MyView { get; private set; } 
 
public MyVM() 
{ 
    mItems = new ObservableCollection<Item>(); 
    ListCollectionView myView = new ListCollectionView(mItems); 
    // Do whatever you want with the view here 
    MyView = myView; 
} 

查看代码:

<ItemsControl ItemsSource="{Binding MyView}" /> 

从 XAML View 创建

创建一个 CollectionViewSource 并设置它的 Source集合的属性。您还可以设置其他属性,例如 Filter ,它将调用代码隐藏来运行过滤器。

查看模型代码:

private ObservableCollection<Item> mItems; 
public IEnumerable<Item> Items { get { return mItems; } } 
 
public MyVM() 
{ 
    mItems = new ObservableCollection<Item>(); 
} 

查看代码:

<Grid> 
    <Grid.Resources> 
        <CollectionViewSource 
            x:Key="MyItemsSource" 
            Source="{Binding Items}" /> 
    </Grid.Resources> 
    <ItemsControl ItemsSource="{Binding Source={StaticResource MyItemsSource}}" /> 
</Grid>