How do I filter items from a collection?
Today I will show you two ways of using the filter feature of data binding.
There are two ObservableCollections of items in this sample. The first one contains a list of GreekGods, and the ListBox that displays it shows their Roman names. The second one contains a list of GreekHeroes. I will use these two collections to show two different ways of filtering items.
I decided to filter out all items that start with “A” from the first collection. I started out by adding a new instance of the GreekGods collection to the resources and bound a ListBox’s ItemsSource to that collection:
<Window.Resources>
<local:GreekGods x:Key="src1"/>
(…)
</Window.Resources>
<Label>Items that start with "A" are filtered out:</Label>
<ListBox ItemsSource="{Binding Source={StaticResource src1}}" DisplayMemberPath="RomanName"/>
In the constructor for the Window, I added code after initialization to get the default view for this collection. Remember that we never bind directly to the collection; there is always a view on top of that collection that we bind to. In this case I am not creating that view explicitly with the help of a CollectionViewSource, so a default view is created behind the scenes. I can get to that default view by using the GetDefaultView static method of CollectionViewSource:
public Window1()
{
InitializeComponent();
object src1 = this.Resources["src1"];
ICollectionView collectionView = CollectionViewSource.GetDefaultView(src1);
collectionView.Filter = new Predicate<object>(FilterOutA);
}
Once I have a handle to the view, I am able to set its Filter property to the Predicate<object> callback function below:
public bool FilterOutA(object item)
{
GreekGod gg = item as GreekGod;
if ((gg == null) || gg.RomanName.StartsWith("A"))
{
return false;
}
else
{
return true;
}
}
This method is called once for each item. If the item is a GreekGod whose Roman name begins with “A”, it will return false, and that item will be filtered out. Otherwise, it will return true and the item will be displayed.
Similarly, I decided to filter out all items that start with B from the second collection. However, this time I am using CollectionViewSource explicitly. I set the Source property of the CollectionViewSource to the collection and bind the ListBox’s ItemsSource to the CollectionViewSource:
<Window.Resources>
(…)
<local:GreekHeroes x:Key="src2"/>
<CollectionViewSource Source="{StaticResource src2}" x:Key="cvs" Filter="FilterOutB"/>
</Window.Resources>
<Label>Items that start with "B" are filtered out:</Label>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}" DisplayMemberPath="HeroName"/>
We came up with the CollectionViewSource class to serve two purposes: 1) To allow us to do view related operations in XAML, such as grouping, sorting, filtering or creating a custom view of a certain type and 2) To serve as a container for all the view methods, such as GetDefaultView or IsDefaultView. Before we came up with this class these methods were in the Binding class, which cluttered it with unrelated methods and made it hard for users to find them.
I’ve been asked several times about the difference between CollectionView and CollectionViewSource. The difference is simple: CollectionViewSource is not a view, but a class that contains handles to the source and the corresponding view and is used for the purposes I described above. CollectionView is an actual view on top of a collection, which contains information about the current item, filtering, sorting and grouping.
Unfortunately you still need code to specify which items are filtered in or out:
private void FilterOutB(object sender, FilterEventArgs e)
{
GreekHero gh = e.Item as GreekHero;
if ((gh == null) || gh.HeroName.StartsWith("B"))
{
e.Accepted = false;
}
else
{
e.Accepted = true;
}
}
Note that the Filter property in CollectionViewSource is not a delegate like the one in CollectionView, but an event handler. We made this decision so that you could specify the name of the filter method in XAML. At this point, there is no support to add the name of the callback method of a delegate in XAML, but this support exists for events. We realize that the two ways of filtering are a little inconsistent, but this design brings us closer to our goal of allowing the user to do as much as possible in XAML with CollectionViewSource.
The filter event handler has a FilterEventArgs argument, which has two interesting properties: the Item property that provides the item on which we need to make the filter decision, and the Accepted property where we set the result of that decision. If we set Accepted to false, the item will be filtered out, and if we set it to true, the item will be displayed.
Here is a screenshot of the completed sample:

Here you can find the VS project with this sample code. This works with July CTP WPF bits.
Posted by Bea under WPF | Comments (14)
Hi Beatriz,
Thanks a lot for your articles! Awesome work. I’m looking forward for new posts.
The only problem – looks like your RSS feed is broken – it says that the most recent post is “How do I show the Status of a Binding?” Apr 4 2006.
paul
Paul,
Thanks a lot for letting me know, I really appreciate it. I will investigate what is going on with my feed.
Bea
Hi Paul,
I fixed the problem with the feed. Let me know if your RSS reader picked it up.
Thanks a lot for letting me know of this issue.
Bea
Great examples. My knowledge is more in COM and XSL and now that it looks like WPF doesn’t support pluggable protocols (COM objects through URLMon), that leaves me only XSL. Is it possible to run some client side xslt to binded XML so that binded elements are automatically updated?
Hi Miksu,
We don’t have any special support for XSLT. However, any change you make to a source XML document will be propagated to the target of the bindings. Did this answer your question?
Bea
Hi!
i want to filter a collection depending on the Text of a Textbox, but the only problem is:
how can i force the CollectionView to refresh the filtering process ??
eiro
Hi Eiro,
There is a Refresh method on CollectionView that allows you to do what you’re looking for.
Thanks!
Bea
I am using a CollectionViewSource and I am unable to find that method, could you please help me out?
Oh, it’s m_CollectionViewSource.View.Refresh()
Yes, that’s one way to get to the view. There are other ways – I explain all the different options in this post.
how does one use a single observable collection, and then have two different control view that single collection in different ways with different filters? i am assuming multiple views on top of the single collection, but am having trouble with the XAML.
Hi Zach,
Your assumption is correct.
You can add two CollectionViewSource instances to the resources, both pointing to the same source data (same Source property), but with different Filter methods. Then you can bind one control to one CVS, and another control to the other.
Let me know if you still have trouble with the syntax.
Bea
Hi Bea,
I am trying to use collectionview filtering with your AsyncVirtualizingCollection over a large underlying data source. The problem is that when a filter predicate is added to the ListCollectionView.Filter it goes off and enumerates over the entire underlying collection applying the filter. I’m wondering if there could be a workaround if I wrote my own ICollectionView so that filtering is applied as late as possible as items are scrolled into view. This would obviously meam that the total filtered items count is unknown. Could this possibly work?
Thanks
Dan
Yep, ListCollectionView’s filtering doesn’t play well with data virtualization.
I have a solution for your problem and can make that my next blog post. So stay tuned – I’ll post it in a few days.
Bea