Wednesday, October 16, 2013

Searching in Windows Phone ListBox

One of the most common way of searching in ListBox is to type text in TextBox and filter the ListBox items. In this article we will see how we can do this in Windows Phone application.



As you can see in above image, we have a TextBox where user can type, and a ListBox which get filtered based on text entered.

XAML Code


<phone:PhoneApplicationPage
    x:Class="PhoneApp1.MainPage"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">
    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12">
            <TextBlock x:Name="ApplicationTitle" TextAlignment="Center"  Text="SEARCHABLE LISTBOX" Style="{StaticResource PhoneTextNormalStyle}"/>
        </StackPanel>
        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
             
            <TextBox Grid.Row="0" Name="txtSearchText"/>
            <ListBox Grid.Row="1" Background="LightGray" Name="lstData" Margin="12,0"/>
        </Grid>
    </Grid>
  
</phone:PhoneApplicationPage>

Windows Phone has a class called CollectionView which allows grouping, sorting, filtering and navigation in a data collection. To create a collection view for a collection that implements IEnumerable, we can create a CollectionViewSource object, and add collection to the Source property. To filter the data based on TextBox text, we have to add event handler for Filter event.

Private Sub BindListBox()
       mTechnologiesCollectionSource.Source = mTechnologies
       Dim b As New Binding
       AddHandler mTechnologiesCollectionSource.Filter, AddressOf mTechnologiesCollectionSource_Filter
       b.Source = mTechnologiesCollectionSource
       lstData.SetBinding(ListBox.ItemsSourceProperty, b)
End Sub
  
  
Private Sub mTechnologiesCollectionSource_Filter(sender As Object, e As FilterEventArgs)
       Dim str As String = e.Item
       If String.IsNullOrWhiteSpace(txtSearchText.Text) = True OrElse str.ToUpperInvariant.StartsWith(txtSearchText.Text.ToUpperInvariant) = True Then
           e.Accepted = True
       Else
           e.Accepted = False
       End If
  
End Sub

In the above code, we are using "StartsWith" function to filter the Collection, and show the items which starts with text typed in TextBox. We can also use "Contains" function instead of "StartsWith" to show all the items which contains text typed in TextBox.

Private Sub mTechnologiesCollectionSource_Filter(sender As Object, e As FilterEventArgs)
       Dim str As String = e.Item
       If String.IsNullOrWhiteSpace(txtSearchText.Text) = True OrElse str.ToUpperInvariant.Contains(txtSearchText.Text.ToUpperInvariant) = True Then
           e.Accepted = True
       Else
           e.Accepted = False
       End If
  
End Sub

On TextChanged event on TextBox to reapply the filter we have to refresh the view using "CollectionViewSource.View.Refresh" function.


Imports System.Collections.ObjectModel
Imports System.Windows.Data
Partial Public Class MainPage
    Inherits PhoneApplicationPage
    Dim mTechnologies As New ObservableCollection(Of String)
    Dim mTechnologiesCollectionSource As New CollectionViewSource
    ' Constructor
    Public Sub New()
        InitializeComponent()
        FillListBox()
    End Sub
    Private Sub FillListBox()
        mTechnologies.Add("HTML")
        mTechnologies.Add("Silverlight")
        mTechnologies.Add("Visual Basic")
        mTechnologies.Add("Visual C#")
        mTechnologies.Add("Visual F#")
        mTechnologies.Add("Window Communication Foundation")
        mTechnologies.Add("Window Presentation Foundation")
        mTechnologies.Add("Window Phone")
        mTechnologies.Add("XML")
        mTechnologies.Add("XAML")
    End Sub
    Private Sub MainPage_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
        BindListBox()
    End Sub
    Private Sub BindListBox()
        mTechnologiesCollectionSource.Source = mTechnologies
        Dim b As New Binding
        AddHandler mTechnologiesCollectionSource.Filter, AddressOf mTechnologiesCollectionSource_Filter
        b.Source = mTechnologiesCollectionSource
        lstData.SetBinding(ListBox.ItemsSourceProperty, b)
    End Sub
    Private Sub mTechnologiesCollectionSource_Filter(sender As Object, e As FilterEventArgs)
        Dim str As String = e.Item
        If String.IsNullOrWhiteSpace(txtSearchText.Text) = True OrElse str.ToUpperInvariant.StartsWith(txtSearchText.Text.ToUpperInvariant) = True Then
            e.Accepted = True
        Else
            e.Accepted = False
        End If
    End Sub
    Private Sub txtSearchText_TextChanged(sender As Object, e As TextChangedEventArgs) Handles txtSearchText.TextChanged
        mTechnologiesCollectionSource.View.Refresh()
    End Sub
End Class

You can also refer following links to know more about CollectionViewSource

http://msdn.microsoft.com/en-us/library/system.windows.data.collectionview.aspx
http://msdn.microsoft.com/en-us/library/ms752348.aspx