Introducing DotNetFunda.com on mobile http://m.dotnetfunda.com ! Be with DotNetFunda.com on the go !
Go to DotNetFunda.com
Twitter TwitterLinkedIn
YouTubeGoogle
 Online : 29838 |  Welcome, Guest!   Register  Login
Home > Articles > WPF > Simple Grid Implementation with ICollectionView in WPF

Simple Grid Implementation with ICollectionView in WPF

1 vote(s)
Rating: 5 out of 5
Article posted by Abhi2434 on 8/29/2010 | Views: 11190 | Category: WPF | Level: Beginner | Points: 150 red flag


ListView is one of the better control in WPF which have lots of flexibilities and empowers to build Grid like control easily. In this article I will discuss how easily you could use ListView to create Grid with Filtering, Grouping, Sorting, Navigating or even with In Place Editors to edit control. This is all in one sample for you.

Download


 Download source code for Simple Grid Implementation with ICollectionView in WPF


Introduction


If you are working with WPF for long, you might already have come across with ICollectionView. It 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.



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.

Using the Code


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





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">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Name}" Style="{StaticResource ListViewUnSelected}"/>
<TextBox Text="{Binding Path=Name}" Style="{StaticResource ListViewSelected}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Developer">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Developer}" Style="{StaticResource ListViewUnSelected}" />
<ComboBox SelectedItem="{Binding Path=Developer}" ItemsSource="{Binding ElementName=mainWin, Path=DeveloperList}" Style="{StaticResource ListViewSelected}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Salary">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Salary}" Style="{StaticResource ListViewUnSelected}" />
<TextBox Text="{Binding Path=Salary}" Style="{StaticResource ListViewSelected}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>

SORT





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));
}
else
this.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.

FILTER




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.

GROUP




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));

NAVIGATE





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

IN PLACE EDITING




In order to show you in-place editing, I have placed a separate control for editing purpose of each of the Selected Row. The selected Item is detected automatically using RelativeSource in the ListView DataColumn selector.

Say for instance :
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Name}" Style="{StaticResource ListViewUnSelected}"/>
<TextBox Text="{Binding Path=Name}" Style="{StaticResource ListViewSelected}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

Here the Style ListViewSelected will show the TextBox while the ListViewUnselected will show the TextBlock. If you look into the Style it will look like :

<Style x:Key="ListViewUnSelected" TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Converter={StaticResource convVis}, ConverterParameter=False}" />
</Style>
<Style x:Key="ListViewSelected" TargetType="{x:Type FrameworkElement}">
<Setter Property="Visibility" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Converter={StaticResource convVis}, ConverterParameter=True}" />
</Style>

The RelativeSource FindAncestor searches the corresponding ListViewItem everytime and Binds it with the IsSelected property of it. Hence when the item gets selected, the CellTemplate automatically gets updated with the Editor controls.


The Evaluate Selected Object button actually shows a short message based on the information in the current selection.

private void btnEvaluate_Click(object sender, RoutedEventArgs e)
{
ViewItem item = this.lvItems.SelectedItem as ViewItem;

string msg = string.Format("Hello {0}, Developer in {1} with Salary {2}", item.Name, item.Developer, item.Salary);
MessageBox.Show(msg);
}

So from the image above you can see Peter is a developer in WPF.


If you change the Developer section from the ComboBox and choose SilverLight, the MessageBox will update the value and hence the internal object is also gets updated.

Notice : I have used reflection to get  PropertyInfo for many cases. If you don't want to use it, you might also do this statically.

Conclusion

In summery, WPF ius the most flexible tool for UI Development. It has lots of flexibilities and the use of few features can really make our life easier. In this article, you got the idea on how to handle ICollectionView for Data Manipulation. If you are really new to this type of programming, why not you start reading my Beginners Tutorial on WPF.

I hope this article comes to you handy. Thank you for reading the post and your valuable feedback.

If you like this article, subscribe to our RSS Feed. You can also subscribe via email to our Interview Questions, Codes and Forums section.

Page copy protected against web site content infringement by Copyscape
Found interesting? Add this to:



Please Sign In to vote for this post.

About Abhishek Sur

Experience:3 year(s)
Home page:http://www.abhisheksur.com
Member since:Wednesday, December 02, 2009
Level:Silver
Status: [Member] [Microsoft_MVP] [MVP]
Biography:Working for last 2 and 1/2 years in .NET environment with profound knowledge on basics of most of the topics on it.
>> Write Response - Respond to this post and get points
Related Posts

Technology is growing, everyday you will hear that there is a new version of something and you will wonder if we will ever stop learning. If you are a Microsoft developer you will always buy books because almost every three or two years they bring something and when you are still busy trying to master the current technology, they introduce something new that is better than this. The gap between .net 2.0 and 3.5 was enough to allow developers to catch up. Well I got affected by that but I kept on touching the chapters of those technologies. I was impressed by all these niceties but I could not have time to explore them all. I came across a WPF and I was impressed by the UI, even if you create a small hello world. I would like to share a small hello world about WPF.

Binding is the most important topic of WPF programming. In this article I have demonstrated how you could employ DataBinding to ensure that the Presentation logic is separated from the View and also give simple demonstration on how the DataBinding concept works. The article also gives you the basics of CommandBinding and MultiBinding.

We will look into three main types of in WPF.

We will see how we can pass parameters to a WPF Click-Once Application and depends on the parameter we can use the application.

This is an Application which can change your default Logon Screen of Windows XP. There are many applications that allow you to do this Application’s like Logon Studio etc. I have developed this simple application in WPF using Vb.Net. You can see how i made it by following the description below. The Application does Not use any DLL’s nor does it use any API so it is very easy to understand.

More ...
About Us | Contact Us | The Team | Advertise | Software Development | Write for us | Testimonials | Privacy Policy | Terms of Use | Link Exchange | Members | Go Top
General Notice: If you found plagiarised (copied) contents on this page, please let us know the original source along with your correct email id (to communicate) for further action.
Copyright © DotNetFunda.Com. All Rights Reserved. Copying or mimicking the site design and layout is prohibited. Logos, company names used here if any are only for reference purposes and they may be respective owner's right or trademarks. | 5/28/2012 11:54:30 AM