WPF: ICollectionView - Фильтровать один список, если элемент содержится в другом списке? - PullRequest
1 голос
/ 27 апреля 2011

По сути, у меня есть 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. Выполнить итерациюсамому ItemSource узнать, содержит ли он элемент?
  3. Использовать метод расширения Cast в LINQ для приведения к 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, поэтому не стоит снова запускать фильтр.Возможно, решение этой части лучше подходит как другой вопрос?Но, если кто-то захочет ответить здесь:

Как я могу заставить свой List1 повторно применить фильтр при изменении коллекции List2?

ОБНОВЛЕНИЕ 3: Я спросилкак подключиться к событию в обмене коллекциями в отдельном вопросе SO и получить мой ответ.

1 Ответ

1 голос
/ 27 апреля 2011

ItemsSource статически объявлен как IEnumerable, но его фактический тип времени выполнения может быть любым, который реализует IEnumerable. Если вы знаете, что на самом деле это ObservableCollection<MyItem>, вы можете просто привести к этому типу:

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

(или вы можете просто привести к IList<MyItem>, поскольку в этом интерфейсе определено Contains)

Linq также хороший вариант:

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