【问题标题】:WPF: ICollectionView - Filter one list if item is contained in another list?WPF:ICollectionView - 如果项目包含在另一个列表中,则过滤一个列表?
【发布时间】:2011-08-13 21:44:52
【问题描述】:

基本上,我有 2 个 ListView,每个都绑定到不同的 ItemsSource

列表 1 不能更改(它是 ReadOnlyObservableCollection)。
列表 2可以更改(通过用户交互)。

我需要在列表 1 中添加一个过滤器,这样它就不会显示在列表 2 中找到的任何内容。这是我目前的代码...

view = CollectionViewSource.GetDefaultView(List1.ItemsSource);
view.Filter += o =>
{
    MyItem item = o as MyItem;
    return List2.ItemsSource.??;
};


List2.ItemsSource 以 IEnumerable 而不是 ObservableCollection (实际上是什么)的形式返回。我想尽可能有效地做到这一点,所以我不确定我是否应该:
  1. 将 ItemsSource 显式转换为 IList 以获得对 Contains 的访问权限?
  2. 自己遍历 ItemsSource 以查看它是否包含该项目?
  3. 使用 LINQ 的 Cast 扩展方法强制转换为 IList(或其他类型)以获得对 Contains 的访问权限?
  4. 还有其他方法吗?

更新:

第一次渲染后似乎没有继续过滤项目:

view = CollectionViewSource.GetDefaultView(List1.ItemsSource);
view.Filter += o =>
{
    MyItem item = (MyItem)o;
    var collection = (ObservableCollection<MyItem>)List2.ItemsSource;
    //return collection.Contains(item);//Filters out ALL items from the list
    return !collection.Contains(item); //Shows all items, but as I add items
                                       //to list 2 it doesn't filter items out of
                                       //list 1.
};

更新 2:

我想我明白为什么它没有重新应用过滤器。原始集合不会引发 CollectionChanged 通知,因此它不会费心再次运行过滤器。也许解决这部分更适合作为不同的问题?但是,如果有人想在这里回答:

当 List2 集合发生变化时,如何让我的 List1 重新应用过滤器?

更新 3: 我在separate SO question 中询问了如何与collectionchanged 事件联系起来,并得到了答案。

【问题讨论】:

    标签: wpf listview filter itemssource icollectionview


    【解决方案1】:

    ItemsSource 静态声明为IEnumerable,但其实际运行时类型可以是任何实现IEnumerable 的类型。如果你碰巧知道它实际上是一个ObservableCollection&lt;MyItem&gt;,你可以直接转换成这个类型:

    view = CollectionViewSource.GetDefaultView(List1.ItemsSource);
    view.Filter += o =>
    {
        MyItem item = (MyItem)o;
        var collection = (ObservableCollection<MyItem>)List2.ItemsSource;
        return collection.Contains(item);
    };
    

    (或者你可以直接转换为IList&lt;MyItem&gt;,因为Contains是在这个接口中定义的)

    Linq 也是一个不错的选择:

    view = CollectionViewSource.GetDefaultView(List1.ItemsSource);
    view.Filter += o =>
    {
        MyItem item = (MyItem)o;
        return List2.ItemsSource.Cast<MyItem>().Contains(item);
    };
    

    【讨论】:

    • 是的,两者似乎都可以正常工作,但我希望知道哪个是最好的(最有效的)。
    • 其实我只是运行了一下,我以为它们运行正常,但似乎没有过滤。很多项目的名称很接近,所以我以为它们被过滤掉了,但事实并非如此......
    • @michael,没有一个比另一个更好,因为它总是会在 List2 上进行线性搜索。第一个选项 (cast) 可能比第二个选项 (Linq .Cast/.Contains) 稍微快一点,但可能并不明显
    • 修改List2时过滤器不会自动刷新。您需要重新分配 ICollectionView 的 Filter 属性才能显式地重新执行过滤器。
    • @Thomas:怎么可能做到这一点?
    猜你喜欢
    • 2015-06-04
    • 2018-02-25
    • 2021-09-28
    • 2020-07-19
    • 1970-01-01
    • 2013-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多