Posts tagged ‘filtering data’

WPF: Dynamic Filtering Data – the simple approach

You often find yourself wanting to quickly filter data based on a criteria defined by a user in an application.  A classic example is filtering what’s shown in a listbox by what a user has typed into a textbox.

There are many approaches to solving the problem but a quick and simple approach is: (first the xaml):

<Window x:Class="Window1"  
  xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation  
  xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml  
  xmlns:local="clr-namespace:contactManager"  
  xmlns:system="clr-namespace:System;assembly=mscorlib" 
  Title="Window1" Height="598" Width="1015">
  <Window.Resources>
     <local:contacts x:Key="myContacts" />    
     <CollectionViewSource x:Key="contactsViewSource"
         Source="{StaticResource myContacts}" Filter="CollectionViewSource_Filter" />

  </Window.Resources>
  <Grid Name="Grid1">
    <Grid.RowDefinitions>
      <RowDefinition Height="60*" />
      <RowDefinition Height="423*" />
    </Grid.RowDefinitions>
    <TextBox Margin="62,26,16,0" Name="txtSearch" Height="23" VerticalAlignment="Top"
     AcceptsReturn="True" FontStyle="Italic" KeyUp="txtSearch_KeyUp" />
    <Label Margin="12,12,66,0" Name="Label1" Height="28" VerticalAlignment="Top">Search</Label>

    <ListBox Grid.Row="1" Name="lstContacts" IsSynchronizedWithCurrentItem="True" 
      ItemsSource="{Binding Source={StaticResource contactsViewSource}}" />
  </Grid>

</Window>

The local resource contacts is a class that is defined in the application.  The namespace is imported into the XAML with xmlns:local=”clr-namespace:contactManager“‘.  The class itself is referenced in XAML by <local:contacts x:Key=”myContacts” />‘.

The class itself inherits from an observableCollection – although the approach would work with any datasource that can be bound to the listbox. After contacts has been imported – we setup a collectionViewSource – rather than using the default viewSource provided by WPF.

The code behind to connect the filter text with the filter applied to the listbox is:

Partial Public Class Window1  
  Private Function findString(ByVal haystack As String, ByVal needle As String, _       
                                 Optional ByVal comparison As StringComparison _          
                                    = StringComparison.CurrentCultureIgnoreCase) As Integer
    ' We are using string.indexOf rather than string.contains as string.contains     
    ' doesn't allow us to specify CurrentCultureIgnoreCase         
    Return haystack.IndexOf(needle, 0, comparison) 

  End Function 

Private Sub CollectionViewSource_Filter(ByVal sender As System.Object, _                                   
                                    ByVal e As System.Windows.Data.FilterEventArgs) 
   ' Cast the listbox item to the type used   
  Dim thisContact As contact = CType(e.Item, contact) 

  If (thisContact IsNot Nothing) Then  ' Handle an empty item 

    If String.IsNullOrEmpty(txtSearch.Text) Then           
      ' Make sure we have some text that we wish to filter

      e.Accepted = True         
      ' If we don't then we want all items to appear in the listbox

    Else                  
      ' findString returns the index of the needle (search text) in       
      ' the haystack (text to be searched)             
      ' IndexOf returns -1 if the needle isn't found in the haystack 

      If (findString(thisContact.firstName, txtSearch.Text) > -1) _                 
               Or (findString(thisContact.lastName, txtSearch.Text) > -1) Then 

        ' The needle exists in the haystack - so accept this entry                 
        e.Accepted = True 

      Else                        
        ' This item doesn't contain the needle we are looking for

        e.Accepted = False

      End If 

    End If

  Else            
    ' thisContact IS nothing - so don't bother displaying it 

    e.Accepted = False 

  End If 

End Sub 

Private Sub txtSearch_KeyUp(ByVal sender As System.Object, _                    
                                ByVal e As System.Windows.Input.KeyEventArgs)          
' This event will be raised whenever the keyUp event occurs on the     
' textbox that we are using to filter         
' Do a simple refresh on the listbox 

    CType(Me.FindResource("contactsViewSource"), CollectionViewSource).View.Refresh() 

  End Sub 

End Class 

  And that's it - a listbox containing items is filtered based on the text typed by the user in a search box.

Technorati Tags: ,,

Advertisements

Sunday 25th November, 2007 at 7:58 pm 2 comments


Recent Posts