Sunday, November 1, 2009

CollectionViewSource in Silverlight

What is CollectionViewSource

The CollectionViewSource is a class that is used in WPF to apply sorting and filtering on Data. We can also use this class in Silverlight 3.
I came across it while studying for my WPF exam and noticed it was also available in Silverlight. So naturally I had a look. It is very easy to use as I will demonstrate below.

So lets have a look.

In this case, we have List of Person we want be able to Filter and Sort correctly.

A person could be defined like this :

public class Person
{
public String FirstName { get; set; }
public String LastName { get; set; }
}

To be able to use a CollectionViewSource we can define it as a resource in our XAML, we could also define it in code, but for this example we will write most in XAML.

<UserControl.Resources>
<local:PersonDataSource key="data">
<CollectionViewSource Source="{Binding Source={StaticResource data}}" x:Key="CollVS">
<CollectionViewSource.SortDescriptions>
<ComponentModel:SortDescription Direction="Descending">
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</UserControl.Resources>

You see here that we defined a "data" datasource, we should create a class that will be able to store the information we need, lets call it PersonDataSource. We could also add some logic here to return some dummy data for now. For this example I chose to simply inherit from ObservableCollection and not add any additional logic, obviously you could use any collection here you would normally use to bind to a datagrid.

To finish our XAML UI, we add a DataGrid to display our data and a TextBox we can use for filtering. In our case we will apply filtering on the LastName.

<StackPanel Orientation="Vertical">
<data:DataGrid ItemsSource="{Binding Source={StaticResource CollVS}}"/>
<TextBox x:Name="filter"/>
</StackPanel>

Now we can define how we are going to do our filtering and make sure the filtering is visible in the User interface.

public MainPage()
{
InitializeComponent();
//Get the CollectionViewSource from the Resource of the UserControl
CollectionViewSource CollVS = (CollectionViewSource)Resources["CollVS"];
//Make sure we update the datagrid when we change our filter
filter.TextChanged += delegate { CollVS.View.Refresh(); };
//Subscribe to the filter event
CollVS.Filter += cvs_Filter;
}

void cvs_Filter(object sender, FilterEventArgs e)
{
e.Accepted = ((Person)e.Item).LastName.ToLower().StartsWith(filter.Text.ToLower());
}

So what did we do here ? First we needed to get our CollectionViewSource from our Resources. The most important thing here is that we do the following :

filter.TextChanged += delegate { CollVS.View.Refresh(); };

If we don't do this, our view will not update and we will not be able to see our filter.

To filter, we can change if an Item should be filtered by setting the Accepted property , the Filter will be called for every element in your collection.

The last step is to implement IComparable on our Person object , this is required by the CollectionViewSource to apply sorting on the Collection. The data will now be automatically sorted as it is filtered.

1 comment: