How to Sort,Filter and Group with ICollectionViewSource in WPF

No.of Views6113
Bookmarked0 times
Downloads 
Votes1
By  abhi2434   On  12 Nov 2010 00:11:12
Tag : WPF , Data Binding
In this article, i will show to how we can use ICollectionView to the data manipulation in different ways in WPF.
emailbookmarkadd commentsprint

Images in this article missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at info@codegain.com

 

Introduction

In this article, i will show to how we can use ICollectionView for data manipulatio in different ways in WPF.The ICollectionView is the primary Data object for any WPF list controls (like ComboBox, ListBox, ListView etc) that allows flexibilities like Sorting, Filtering, Grouping, Current Record Management etc. Thus it ensures that all the related information like filtering, sorting etc is decoupled from the actual control.  It is been very popular to those working with data object because of inbuilt support for all WPF List controls. So I thought I would consider to describe it a bit so that people might easily plug in the same to their own solution.

What is a CollectionView ?

It is a layer that runs over the Data Objects which allows you to define rules for Sorting, Filtering, Grouping etc and manipulate the display of data rather than modifying the actual data objects. Therefore in other words, a CollectionView is a class which takes care of the View totally and giving us the capability to handle certain features incorporated within it.

How to Get a CollectionView ?

Practically speaking, getting a CollectionView from an Enumerable the most easiest thing I ever seen in WPF. Just you need to pass the Enumerable to CollectionViewSource.GetDefaultView. Thus rather than defining.

this.ListboxControl.ItemsSource = this.Source;

you need to write ,

this.ListboxControl.ItemsSource = CollectionViewSource.GetDefaultView(this.Source);

The List will get the CollectionView it requires.

The Overview of Process flow 

Image Loading

So the CollectionView actually separates the View object List Control with the actual DataSource and hence gives an interface to manipulate the data before reflecting to the View objects. Now let us look how to implement the basic features for the ICollectionView.

Sorting

Sorting can be applied to the CollectionView in a very easy way. You need to add a SortDescription to the CollectionView. The CollectionView actually maintains a stack of SortDescription objects, each of them being a Structure can hold information of a Column and the Direction of Sorting. You can add them in the collectionView to get desired output.

Say I store the CollectionView as a property :

ICollectionView Source { get; set; }

Now if you want to sort the existing collection.

this.Source.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Descending));

Hence the CollectionView will be sorted based on Name and in Descending order.

Note : The default behavior of CollectionView automatically Refresh when a new SortDescription is added to it. For performance issue, you might use DeferRefresh() if you want to refresh only once to add SortDescription more than once.

Grouping

You can create custom group for ICollectionView in the same way as you do for sorting. To create Group of elements you need to use GroupStyle to define the Template for the Group and to show the name of the Group in Group Header.

<listview.groupstyle>
	<GroupStyle>
		<GroupStyle.HeaderTemplate>
			<DataTemplate>
				<TextBlock Text="{Binding Name}" />
			</DataTemplate>
		</GroupStyle.HeaderTemplate>
	</GroupStyle>
</listview.groupstyle>

Here we define the Group HeaderTemplate for each groups so that the TextBlock shows the name of the Group item by which the grouping is made. You can specify more than one Grouping information for a single collection. To group a collection you need to use :

this.Source.GroupDescriptions.Add(new PropertyGroupDescription("Department"));

Note : Grouping turns off virtualization. So if you are dealing with large amount of data, Grouping may lead to performance issue.

You can apply custom grouping as well by defining IValueConverter in PropertyGroupDescription as well.

Filtering

Filtering requires a delegate (Predicate) based on which the filter will occur. The Predicate takes in the item an based on the value true or false it returns, it selects or unselect an element.

this.Source.Filter = item =>
        {    
            ViewItem vitem = item as ViewItem;
            if (vitem == null) 
                return false;
            return  
                vitem.Name.Contains("A");
        };

This will select only the elements which have A in their names.

Current Record Manipulation

ICollectionView also allows to synchronize items with the Current position of the element in the CollectionView. Each ItemsControl which is the base class of any ListControl in WPF exposes a property called IsSynchronizedWithCurrentItem when set to true will automatically keeps the current position of the CollectionView in synch.

There are methods like :

this.Source.MoveCurrentToFirst();
this.Source.MoveCurrentToPrevious();
this.Source.MoveCurrentToNext();
this.Source.MoveCurrentToLast();

These allows you to navigate around the CurrentItem of the CollectionView.You can also use CurrentChanged event to intercept your selection logic around the object.

Sample Application

To demonstrate all the features, I have created on Demo application which allows you to Sort, Filter, Group and navigate between data objects. Lets see how it works : 

Image Loading

The application contains a ListView with few data in it. The header is created using GridView which can be clicked and based on which the items will sort.

<ListView ItemsSource="{Binding}" x:Name="lvItems" GridViewColumnHeader.Click="ListView_Click" IsSynchronizedWithCurrentItem="True" Grid.Row="1">
	<ListView.GroupStyle>
		<GroupStyle>
			<GroupStyle.HeaderTemplate>
				<DataTemplate>
					<TextBlock Text="{Binding Name}" />
				</DataTemplate>
			</GroupStyle.HeaderTemplate>
		</GroupStyle>
	</ListView.GroupStyle>
	<ListView.View>
		<GridView AllowsColumnReorder="True">
			<GridViewColumn Header="Id" DisplayMemberBinding="{Binding Id}" />
			<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
			<GridViewColumn Header="Developer">
				<GridViewColumn.CellTemplate>
					<DataTemplate>
						<TextBlock Text="{Binding Path=Developer}" />
					</DataTemplate>
				</GridViewColumn.CellTemplate>
			</GridViewColumn>
			<GridViewColumn Header="Salary">
				<GridViewColumn.CellTemplate>
					<DataTemplate>
						<TextBlock Text="{Binding Path=Salary}" />
					</DataTemplate>
				</GridViewColumn.CellTemplate>
			</GridViewColumn>
		</GridView>
	</ListView.View>
</ListView>

 Image Loading

In the above image it is shown how the items automatically gets sorted when the header is clicked. To handle this I have used GridViewColumnHeader.Click which allows you to get control over the column in which it is clicked.

private void ListView_Click(object sender, RoutedEventArgs e){         
        GridViewColumnHeader currentHeader = e.OriginalSource as GridViewColumnHeader;if(currentHeader != null && currentHeader.Role != GridViewColumnHeaderRole.Padding){using (this.Source.DeferRefresh()){                    
                Func<SortDescription, bool> lamda = item => item.PropertyName.Equals(currentHeader.Column.Header.ToString());if (this.Source.SortDescriptions.Count(lamda) > 0){                      
                    SortDescription currentSortDescription = this.Source.SortDescriptions.First(lamda);     
                    ListSortDirection sortDescription = currentSortDescription.Direction == ListSortDirection.Ascending ? 
                        ListSortDirection.Descending : ListSortDirection.Ascending;     
                    currentHeader.Column.HeaderTemplate = currentSortDescription.Direction == ListSortDirection.Ascending ?this.Resources["HeaderTemplateArrowDown"] as DataTemplate : this.Resources["HeaderTemplateArrowUp"] as DataTemplate;this.Source.SortDescriptions.Remove(currentSortDescription);this.Source.SortDescriptions.Insert(0, new SortDescription(currentHeader.Column.Header.ToString(), sortDescription));}elsethis.Source.SortDescriptions.Add(new SortDescription(currentHeader.Column.Header.ToString(), ListSortDirection.Ascending));}}}

 In the above code I need to handle the Sorting gracefully so that we always remove the current Sorting before we insert a new sort.

Image Loading

The FilterBy section allows you to handle Filtering. You can select the ColumnName from the ComboBox and then apply the selection criteria for the column. To do this I have used FilterButton Click command.

this.Source.Filter = item =>{             
            ViewItem vitem = item as ViewItem;if (vitem == null)return false;  
            PropertyInfo info = item.GetType().GetProperty(cmbProperty.Text);if (info == null) return false;return  info.GetValue(vitem,null).ToString().Contains(txtFilter.Text);};

 Hence the predicate will be applied to the filter criteria.

Image Loading

You can use Grouping Section to group based on Column Name. Here you can see I have grouped items on Developer names. The applied group header will be shown in the Group Header section.

this.Source.GroupDescriptions.Clear();
        PropertyInfo pinfo = typeof(ViewItem).GetProperty(cmbGroups.Text);
        if (pinfo != null)
            this.Source.GroupDescriptions.Add(new PropertyGroupDescription(pinfo.Name));

 

Image Loading

Navigation is handled using a sets of buttons which eventually calls the respective methods to automatically keep CollectionView in sync with ListView items.

Notice : I have used reflection to get  PropertyInfo for many cases. If you dont want to use, you might also do this statically. I have used reflection only to handle this dynamically.

Conclusion

Through this article, we have learned,how we can use ICollectionView to the data manipulation in different ways in WPF.and also access current position data from the collection as well.

Download Sample Project

Download source files -87 kb

 
Sign Up to vote for this article
 
About Author
 
abhi2434
Occupation-Not Provided
Company-Not Provided
Member Type-Senior
Location-Not Provided
Joined date-22 Oct 2009
Home Page-Not Provided
Blog Page-Not Provided
 
 
Other popularSectionarticles
Comments
There is no comments for this articles.
Leave a Reply
Title:
Display Name:
Email:
(not display in page for the security purphase)
Website:
Message:
Please refresh your screen using Ctrl+F5
If you can't read this number refresh your screen
Please input the anti-spam code that you can read in the image.
^ Scroll to Top
</