How to Navigate, Group, Sort and Filter Data in WPF
What is a CollectionView?
Navigation
Filtering
Sorting
Grouping
How to create a CollectionView in XAML
What is a CollectionView?
WPF has a powerful data binding infrastructure. It allows you to bind almost any kind of collection directly to a view. But when it comes to sorting, filtering and grouping the support of the collections is rare. That's the point where the CollectionView comes into play. A collection view is a wrapper around a collection that provides the following additional features:
- Navigation
- Sorting
- Filtering
- Grouping
How to Create and Use a CollectionView
The following example shows you how to create a collection view and bind it to a ListBox
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListBox ItemsSource={Binding Customers} />
</Window>
public class CustomerView
{
public CustomerView()
{
DataContext = new CustomerViewModel();
}
}
public class CustomerViewModel
{
private ICollectionView _customerView;
public ICollectionView Customers
{
get { return _customerView; }
}
public CustomerViewModel()
{
IList<Customer> customers = GetCustomers();
_customerView = CollectionViewSource.GetDefaultView(customers);
}
}
Navigation
The collection view adds support for selection tracking. If you set the property IsSynchronizedWithCurrentItem to True on the view that the collection is bound to, it automatically synchronizes the current item of the CollectionView and the View.
<ListBox ItemsSource="{Binding Customers}" IsSynchronizedWithCurrentItem="True" />
If you are using a MVVM (Model-View-ViewModel) pattern, you don't have to extra wire-up the SelectedItem of the control, because it's implicity available over the CollectionView.
IList<Customer> customers = GetCustomers();
ICollectionView _customerView = CollectionViewSource.GetDefaultView(customers);
_customerView.CurrentChanged = CustomerSelectionChanged;
private CustomerSelectionChanged(object sender, EventArgs e)
{
// React to the changed selection
}
You can also manually control the selection from the ViewModel by calling the MoveCurrentToFirst() or MoveCurrentToLast() methods on the CollectionView.
Filtering
To filter a collection view you can define a callback method that determines if the item should be part of the view or not. That method should have the following signature:
bool Filter(object item) . Now set the delegate of that method to the Filter property of the CollectionView and you're done.
ICollectionView _customerView = CollectionViewSource.GetDefaultView(customers);
_customerView.Filter = CustomerFilter
private bool CustomerFilter(object item)
{
Customer customer = item as Customer;
return customer.Name.Contains( _filterString );
}
Refresh the filter
If you change the filter criteria and you want to refresh the view, you have to call Refresh() on the collection view
public string FilterString
{
get { return _filterString; }
set
{
_filterString = value;
NotifyPropertyChanged("FilterString");
_customerView.Refresh();
}
}
Sorting
Sorting data ascending or descending by one or multiple criterias is a common requirement for viewing data. The collection view makes it so easy to achieve this goal. Just add as many SortDescriptions as you like to the CollectionView
ICollectionView _customerView = CollectionViewSource.GetDefaultView(customers);
_customerView.SortDescriptions.Add(
new SortDescription("LastName", ListSortDirection.Ascending );
_customerView.SortDescriptions.Add(
new SortDescription("FirstName", ListSortDirection.Ascending );
Fast Sorting
The sorting technique explained above is really simple, but also quite slow for a large amount of data, because it internally uses reflection. But there is an alternative, more performant way to do sorting by providing a custom sorter.
ListCollectionView _customerView = CollectionViewSource.GetDefaultView(customers);
as ListCollectionView;
_customerView.CustomSort = new CustomerSorter();
public class CustomerSorter : IComparer
{
public int Compare(object x, object y)
{
Customer custX = x as Customer;
Customer custY = y as Customer;
return custX.Name.CompareTo(custY.Name);
}
}
Grouping
Grouping is another powerful feature of the CollectionView. You can define as many groups as you like by adding GroupDescriptions to the collection view.
Note: Grouping disables virtualization! This can bring huge performance issues on large data sets. So be careful when using it.
ICollectionView _customerView = CollectionViewSource.GetDefaultView(customers);
_customerView.GroupDescriptions.Add(new PropertyGroupDescription("Country"));
To make the grouping visible in the view you have to define a special GroupStyle on the view.
<ListBox ItemsSource="{Binding Customers}">
<ListBox.GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</ListBox.GroupStyle>
</ListBox>
How to create a CollectionView in XAML
It's also possible to create a CollectionView completely in XAML
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<CollectionViewSource Source="{Binding}" x:Key="customerView">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Country" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<ListBox ItemSource="{Binding Source={StaticResource customerView}}" />
</Window>
Last modified: 2009-10-13 09:25:17
Copyright (c) by Christian Moser, 2011.
Comments on this article
Show all comments
|
tsahi | |
|
Commented on 29.September 2009 |
I think there's an error in the first C# code piece. You cannot declare the variable _customerView without it's type, and in the CustomerViewModel ctor, you probably didn't mean to redefine that variable locally.
|
|
|
|
Christian Moser | |
|
Commented on 2.October 2009 |
Hi Tsahi,
thanks for your feedback. It must have been already a bit late as I wrote this article :-) I correted the two things in the code snippets.
Greetings
Christian
|
|
|
|
jyanks | |
|
Commented on 29.October 2009 |
It'd be really helpful if you indicated which files each code snippet pertains to...
|
|
|
|
Tomas | |
|
Commented on 11.November 2009 |
Ehhm, where does the GetCustomers() method come from? Or am I to inexperienced to realize this...
|
|
|
|
Christian Moser | |
|
Commented on 11.November 2009 |
Hi Thomas,
the GetCustomer() is just a method on the ViewModel that returns a list of customers. I did not mentioned it in the snippet, because it's not relevant where the customers come from. It's just a data source. You can replace it by any kind of data source you like.
I hope this helps.
Christian
|
|
|
|
Nigel Stratton | |
|
Commented on 19.November 2009 |
Love the layout, concept and training, keep it up!
I think your snippet needs a couple of changes, adding "new EventHandler(" and the "void" return type.
_customerView.CurrentChanged += new EventHandler(CustomerSelectionChanged);
private void CustomerSelectionChanged(object sender, EventArgs e)
{
// React to the changed selection
}
Regards,
Nigel
|
|
|
|
Steven Jackson | |
|
Commented on 23.November 2009 |
Thanks for this article, time for me to refactor.
|
|
|
|
anon | |
|
Commented on 7.January 2010 |
But with out a definition for GetCustomers(), teh code can't be used! Its worthwhile you provide the whole code necessary when you write a tutorial for beginners so we dont get lost for hours! :)
|
|
|
|
Andy | |
|
Commented on 12.February 2010 |
"Commented on 7.January 2010
But with out a definition for GetCustomers(), teh code can't be used! Its worthwhile you provide the whole code necessary when you write a tutorial for beginners so we dont get lost for hours! :)"
Just write whatever function or data source you like since the only thing that matters is that it returns results in form GetCustomers() returns.
|
|
|
|
Thomas | |
|
Commented on 16.February 2010 |
Thanks for this article, and very nice site !
but i still have a question, how can you get the number of visible items in your filtered CollectionView ?
|
|
|
|
Mutia | |
|
Commented on 10.June 2010 |
I'm trying to bind and sort and filter images.. how can i posibly do this?
(http://mutiarar06.student.ipb.ac.id)
|
|
|
|
Tod | |
|
Commented on 8.July 2010 |
lol
|
|
|
|
Christian M | |
|
Commented on 23.August 2010 |
I apprieciate your feedback but I cant explain it anymore in depth because I just copy and pasted this from another website
|
|
|
|
alimbada | |
|
Commented on 1.November 2010 |
What is "customers" here? (last line in first example)
_customerView = CollectionViewSource.GetDefaultView(customers);
Or is that supposed to be "Customers"?
|
|
|
|
amir | |
|
Commented on 17.December 2010 |
hello
please help me?
this code for set group style in combo box. i can not set group style .until change combo box items then change text group!!!!
//class person
Public Class Person
Sub New(ByVal d As Integer, ByVal fm As String)
_id = d
_family = fm
End Sub
Private _family As String
Public Property Family() As String
Get
Return _family
End Get
Set(ByVal value As String)
_family = value
End Set
End Property
Private _id As Integer
Public Property ID() As Integer
Get
Return _id
End Get
Set(ByVal value As Integer)
_id = value
End Set
End Property
End Class
//vb.net code
Dim lst As Person() = New Person() {New Person(1, "amir"), New Person(1, "ali"), New Person(2, "hasan"), New Person(3, "ahmad")}
Dim p As New ListCollectionView(lst)
p.Filter = AddressOf compare
p.GroupDescriptions.Add(New PropertyGroupDescription("ID"))
p.SortDescriptions.Add(New ComponentModel.SortDescription("ID", ComponentModel.ListSortDirection.Ascending))
cmb1.DisplayMemberPath = "Family"
cmb1.Items.Clear()
cmb1.ItemsSource = p
Dim g As New GroupStyle
g.HeaderTemplate = New DataTemplate
g.HeaderTemplate.VisualTree = New FrameworkElementFactory(GetType(TextBlock))
With g.HeaderTemplate.VisualTree
Dim b As New Binding("ID")
b.Source = p
.SetBinding(TextBlock.TextProperty, b)
.SetValue(TextBlock.BackgroundProperty, Brushes.Gray)
.SetValue(TextBlock.HeightProperty, 25.0)
.SetValue(TextBlock.ForegroundProperty, Brushes.White)
End With
cmb1.GroupStyle.Add(g)
|
|
|
|
Aarti Varadkar | |
|
Commented on 22.December 2010 |
Check out d link for ICollectionView in detail
http://marlongrech.wordpress.com/2008/11/22/icollectionview-explained/
|
|
|
|
Aarti Varadkar | |
|
Commented on 22.December 2010 |
Check out d link for ICollectionView in detail
http://marlongrech.wordpress.com/2008/11/22/icollectionview-explained/
|
|
|
|
Sanjay Patolia | |
|
Commented on 26.March 2011 |
I understood Itemsource property bindings but Why we use source property while we create collection view in View(XAML).
|
|
|
|
KC | |
|
Commented on 19.May 2011 |
"I apprieciate your feedback but I cant explain it anymore in depth because I just copy and pasted this from another website" - Chritian M
Nice!!!
|
|
|
|
john_stashek | |
|
Commented on 26.August 2011 |
[color=red]Hello, dear users.[/color]
My name is James. Today i was joined in your portal. There are very nice! :) I hope we will be friends.
Appreciate song, please: [url=http://baseofmp3.com/?q=%CC%E0%F5%E0%E1%E1%E0%F2]Махаббат[/url]
I like it.
[b] John[/b].
|
|
|
|