Like sorting,
filtering in a
CollectionViewSource
is not automatically done when you change the contents of one of the data bound items. By default, you need to call the
Refresh
method of the
CollectionViewSource
.
In the example below, we filter on first name “Joan” and then change Joan Fontaine’s first name to “Bob”. Notice that the list is
not
re-filtered–Bob remains in the list.
You can fix this by adding the
FirstName
property to the
LiveFilteringProperties
collection of the
CollectionViewSource
and setting
IsLiveFilteringRequested
to
true
.
<CollectionViewSource x:Key="cvsActors" Source="{Binding ActorList}"
IsLiveFilteringRequested="True">
<CollectionViewSource.LiveFilteringProperties>
<clr:String>FirstName</clr:String>
</CollectionViewSource.LiveFilteringProperties>
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="LastName" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
Now, when we change Joan to Bob and we’re filtering on “Joan”, Bob automatically disappears from the list.
By default, when you’re
using a
CollectionViewSource
to do sorting, grouping and filtering in a list-based control, the sorting/grouping/filtering behavior will
only updated when you explicitly refresh
the
CollectionViewSource
(by calling
Refresh
) or when you add or remove something to the collection.
You can enable
live sorting
in the
CollectionViewSource
to cause it to resort items when one or more properties on the bound objects change. In the example below, we set the
IsLiveSortingRequested
property to
true
and specify that the
Actor.LastName
property is the property to live sort on.
<Window.Resources>
<CollectionViewSource x:Key="cvsActors" Source="{Binding ActorList}"
IsLiveSortingRequested="True">
<CollectionViewSource.LiveSortingProperties>
<clr:String>LastName</clr:String>
</CollectionViewSource.LiveSortingProperties>
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="LastName" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
Now when we make a change to the last name of one of the actors, the sorting is updated.
By default, when you’re
using a
CollectionViewSource
to do sorting, grouping and filtering in a list-based control, the sorting/grouping/filtering behavior will only updated when you explicitly refresh the
CollectionViewSource
(by calling
Refresh
) or when you add or remove something to the collection.
For example, if we add an actor to a list of actors and we are sorting by last name, the actor will be inserted at the correct spot.
When
populating a
ListBox
from a
CollectionViewSource
, you can also filter the data. Below is an example of a
ListBox
that is bound to a
CollectionViewSource
.
<Window.Resources>
<CollectionViewSource x:Key="cvsActors" Source="{Binding ActorList}" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="LastName" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
<StackPanel>
<ListBox Name="lbActors" Margin="15" Width="200" Height="200"
ItemsSource="{Binding Source={StaticResource cvsActors}}"/>
<CheckBox Content="Only Joans" IsChecked="{Binding OnlyJoans}"
Margin="15"/>
</StackPanel>
In code, we add a handler for the
Filter
event of the
CollectionViewSource
. The handler is called for each item in the list.
// Requires: using System.Windows.Data
((CollectionViewSource)this.Resources["cvsActors"]).Filter += ActorList_Filter;
In the handler, we set the
Accepted
property of the argument if the item should be included in the list.
void ActorList_Filter(object sender, FilterEventArgs e)
// Set e.Accepted to true to include the item in the list
if (!onlyJoans)
e.Accepted = true;
Actor a = e.Item as Actor;
e.Accepted = (a.FirstName == "Joan") ? true : false;
We also have to make sure to “refresh” the
CollectionViewSource
when the
OnlyJoans
property changes. This will trigger it to re-filter the collection.
private bool onlyJoans;
public bool OnlyJoans
get { return onlyJoans; }
if (value != onlyJoans)
onlyJoans = value;
RaisePropertyChanged("OnlyJoans");
((CollectionViewSource)this.Resources["cvsActors"]).View.Refresh();
You can
group items in a
ListBox
using a
CollectionViewSource
.
You can then set the
GroupStyle
property of the
ListBox
to be an
Expander
control so that the groups can be expanded and collapsed.
In the example below, we group a collection of
Actors
by the decade of their birth.
<Window.Resources>
<CollectionViewSource x:Key="cvsActors" Source="{Binding ActorList}" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="DecadeBorn" />
<scm:SortDescription PropertyName="LastName" />
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<data:PropertyGroupDescription PropertyName="DecadeBorn"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<StackPanel>
<ListBox Name="lbActors" Margin="15" Width="200" Height="240"
ItemsSource="{Binding Source={StaticResource cvsActors}}">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander Header="{Binding Name}" IsExpanded="True">
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
</ListBox>
</StackPanel>
We can now expand and collapse the groups representing an actor’s birth decade.
Similar to how you can
use a
CollectionViewSource
to sort
a collection of items in a
ListBox
, you can also use the
CollectionViewSource
to group the items, based on a property on the underlying object that you’re binding to.
Assume that you have an
Actor
object that has a
LastName
property and a
DecadeBorn
property that indicates what decade an actor was born in. You can group the actors by decade and then sort within each decade by last name as shown below.
<Window.Resources>
<CollectionViewSource x:Key="cvsActors" Source="{Binding ActorList}" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="DecadeBorn" />
<scm:SortDescription PropertyName="LastName" />
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<data:PropertyGroupDescription PropertyName="DecadeBorn"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<StackPanel>
<ListBox Name="lbActors" Margin="15" Width="200" Height="240"
ItemsSource="{Binding Source={StaticResource cvsActors}}">
<ListBox.GroupStyle>
<GroupStyle/>
</ListBox.GroupStyle>
</ListBox>
</StackPanel>
The empty
GroupStyle
element will cause the group to be rendered using a string representation of the
DecadeBorn
property.
We sort by decade and by last name within each decade.
You can sort items within a
ListBox
using a
CollectionViewSource
, which is a wrapper around a view of a collection. The
CollectionViewSource
provides support for sorting, filtering and grouping items in the underlying collection. It provides a mechanism for configuring the view from XAML.
In the example below, we define a
CollectionViewSource
that wraps a collection of
Actor
objects and specifies a property to sort on (the actor’s last name). Our
ListBox
then binds to the
CollectionViewSource
rather than to the collection.
<Window.Resources>
<CollectionViewSource x:Key="cvsActors" Source="{Binding ActorList}" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="LastName" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
<StackPanel>
<ListBox Name="lbActors" Margin="15" Width="200" Height="190"
ItemsSource="{Binding Source={StaticResource cvsActors}}"/>
</StackPanel>
The
Actor
objects in our
ListBox
are now sorted by their
LastName
. (
LastName
is a property of the
Actor
object).
Blog Stats
-
5,331,684 hits
Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here:
Cookie Policy