WPF: ICollectionView - Filter one list if item is contained in another list?
Basically, I have 2 ListView's each binding to a different ItemsSource
.
List 1 can not be changed (it's a ReadOnlyObservableCollection
).
I need to add a filter to List 1 so that it doesn't display anything that's found in List 2. This is my code so far...
view = CollectionViewSource.GetDefaultView(List1.ItemsSource);
view.Filter += o =>
{
MyItem item = o as MyItem;
return List2.ItemsSource.??;
};
List2.ItemsSource comes back as an IEnumerable instead of ObservableCollection (what it really is). I want to do this as efficiently as possible, so I wasn't sure if I should:
- Explicitly Cast the ItemsSource as a IList to gain access to Contains?
- Iterate through the the ItemsSource myself to see if it contains the item?
- Use LINQ's Cast extension method to cast to an IList (or some other type) to gain access to Contains?
- Any other way?
UPDATE:
It doesn't seem to continue filtering items after the first time it renders:
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开发者_StackOverflow.Contains(item); //Shows all items, but as I add items
//to list 2 it doesn't filter items out of
//list 1.
};
UPDATE 2:
I think I understand why it's not reapplying the filter. The original collection is not raising a CollectionChanged notification, so it doesn't bother to run the filter again. Perhaps solving this part is better suited as a different question? But, in case anyone wants to answer it here:
How can I get my List1 to reapply the filter when the List2 collection changes?
UPDATE 3: I asked how to tie into the collectionchanged event in a separate SO question and got my answer.
ItemsSource
is statically declared as an IEnumerable
, but its actual runtime type can be anything that implements IEnumerable
. If you happen to know that it's actually an ObservableCollection<MyItem>
, you can just cast to this type:
view = CollectionViewSource.GetDefaultView(List1.ItemsSource);
view.Filter += o =>
{
MyItem item = (MyItem)o;
var collection = (ObservableCollection<MyItem>)List2.ItemsSource;
return collection.Contains(item);
};
(or you can just cast to IList<MyItem>
, since Contains
is defined in this interface)
Linq is also a good option:
view = CollectionViewSource.GetDefaultView(List1.ItemsSource);
view.Filter += o =>
{
MyItem item = (MyItem)o;
return List2.ItemsSource.Cast<MyItem>().Contains(item);
};
精彩评论