Silverlight DataGrid ItemsSource Filter

February 19, 2009 08:07 by wjchristenson2

In this post, I am going to show how to easily filter a collection of objects without creating a whole new collection.  We’ll be filtering collections which implement the IEnumerable interface. Specifically we’ll be casting our collection to an IEnumerable(Of T) which exposes the enumerater and is used to iterate over a collection of a specified type.

Personally I’ve used the IEnumerable(Of T) to filter a DataGrid in Silverlight.  When you want to bind data to the DataGrid, you set the ItemsSource property to your collection.  We’ll simply filter the DataGrid’s ItemsSource collection.  Here’s what our Silverlight filtering application looks like:

First, let’s setup our UI.  I’m going to create a collection of people.  Each person has a name and an age.  We want to filter on age.  Therefore the UI will have a ComboBox so we can select an age to filter on.  We’ll also have a filter Button and a clear filter Button.  We’ll finally have a DataGrid to display our filtered (or unfiltered) results.  Here’s the XAML to produce the UI:

<UserControl x:Class="FilterCollection.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" 
    Width="400" Height="250">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="25" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition Width="75" />
            <ColumnDefinition Width="75" />
        </Grid.ColumnDefinitions>
          
        <ComboBox x:Name="cbxAge" Grid.Column="0" Grid.Row="0" Height="25"  />
        <Button x:Name="btnFilter" Content="Filter" Grid.Column="1" Grid.Row="0" Height="25" Width="70" Margin="5,0,0,0" />
        <Button x:Name="btnClear" Content="Clear" Grid.Column="2" Grid.Row="0" Height="25" Width="70" Margin="5,0,0,0" />
        <data:DataGrid x:Name="dgResults" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="3" AutoGenerateColumns="True" Margin="0,5,0,0" />
    </Grid>
</UserControl>

Before we can create our collection of people, we’ll first need to create a Person object/class.  Here’s the code to accomplish this:

Public Class Person
    Private _Name As String
    Private _Age As Integer

    Public Property Name() As String
        Get
            Return _Name
        End Get
        Set(ByVal value As String)
            _Name = value
        End Set
    End Property

    Public Property Age() As Integer
        Get
            Return _Age
        End Get
        Set(ByVal value As Integer)
            _Age = value
        End Set
    End Property

    Public Sub New(ByVal name As String, ByVal age As Integer)
        _Name = name
        _Age = age
    End Sub
End Class

 

Now that we have our UI and Person object ready, we can finally create our collection and initialize our UI.  I first create the Persons collection, then create a collection of Age(s) to filter by.  I then bind the ComboBox and the DataGrid to our collections.  Keep in mind that the DataGrid is not filtered at this point.

'initialize our collection of person(s)
_Persons = New List(Of Person)
_Persons.Add(New Person("Jake", 29))
_Persons.Add(New Person("Same", 28))
_Persons.Add(New Person("Beth", 29))
_Persons.Add(New Person("Sue", 13))
_Persons.Add(New Person("Tina", 12))
_Persons.Add(New Person("Pete", 13))
_Persons.Add(New Person("Andy", 10))
_Persons.Add(New Person("Ashley", 11))
_Persons.Add(New Person("Sydney", 10))

'initialize our combobox of ages
Dim ages As List(Of Integer) = New List(Of Integer)
For i As Integer = 1 To 30 Step 1
    ages.Add(i)
Next
Me.cbxAge.ItemsSource = ages
Me.cbxAge.SelectedIndex = 0

'initialize our DataGrid to our collection of person(s)
Me.dgResults.ItemsSource = _Persons

Now we are ready to make the magic happen.  When we select an Age and press our Filter Button, we want to filter the _Persons collection and rebind the DataGrid.  Here’s the code:

'acquire the age to filter on
Dim age As Integer = DirectCast(Me.cbxAge.SelectedItem, Integer)

'convert our Persons collection to an IEnumerable(Of T) where T (type) = Person
Dim source As IEnumerable(Of Person) = DirectCast(_Persons, IEnumerable(Of Person))

'filter the collection using the "Where" extension method
Me.dgResults.ItemsSource = source.Where(Function(p As Person) p.Age = age)

We first acquire the selected Age.  Then we convert our collection of Person(s) to an IEnumerable(Of Person).  This allows us to use the IEnumerable(Of T).Where method extension.  Notice I’ve passed in a function to the Where predicate to test each Person to see whether their Age is equal to the selected age.  Only people who’s age is equal to our filter will be bound to the DataGrid.  Here is a picture of our filtered DataGrid:

If we want to clear our filter, we simply set the ItemsSource of our DataGrid back to the original _Persons collection.

'reset the DataGrid's ItemsSource back to our original Persons collection
Me.dgResults.ItemsSource = _Persons

FilterCollection_Soln.zip (1.02 mb)

Bookmark and Share