Google WindowsPhone ListBox Search: HightLight the search result text with specific color(C#-XAML) | SubramanyamRaju Xamarin & Windows App Dev Tutorials

Thursday, 19 June 2014

WindowsPhone ListBox Search: HightLight the search result text with specific color(C#-XAML)

Introduction:

In prev post i was explained about get child items in windowsphone,this post is explained about "How to filter/search the listbox items based on text entered in SearchTextBox?" & "How to highlight the search text color in every mapped listbox items?".Oh apart from these two questions ,for the first question there is lot of resources are available to do that,in other hand second question is very interesting requirement and it is little bit complicated to dynamically highlight listbox items text color  which is mapped by text entered in SearchTextBox . Because indirectly it is the way of communication between SearchTextBox & ListBox DataTemplate controls,so we need to get child items of listbox datatemplate and then dynamically format the child items text color with " Run " object element.However this post will gives you simple solution for above both two questions.

Building the sample:

This sample is targeted on windowsphone 7.1 OS.

Description:

I hope you understand the sample in earlier discussion from "Introduction" section.if you still any confusions see the below image to understand the sample 
Now its time to start implement above functionality in windowsphone using c# & xaml.So we need to have following steps:

1)ListBox binding with C#-XAML in windowsphone:

XAML

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"            <Grid.RowDefinitions                <RowDefinition Height="80"/> 
                <RowDefinition Height="auto"/> 
            </Grid.RowDefinitions> 
            <TextBox Grid.Row="0"  x:Name="SearchTextBox" TextChanged="contactFilterString_TextChanged" Margin="0,0,2,10"/> 
            <ListBox BorderBrush="#FF141EE4" Height="auto" BorderThickness="2" MaxHeight="580" Grid.Row="1" x:Name="listBoxobj" LayoutUpdated="listBoxobj_LayoutUpdated"                <ListBox.ItemTemplate                    <DataTemplate                        <Grid Background="Gray" Width="480"                            <Border BorderBrush="White" BorderThickness="1"                                <Grid                                    <Grid.RowDefinitions                                        <RowDefinition Height="Auto"/> 
                                        <RowDefinition Height="Auto"/> 
                                     </Grid.RowDefinitions> 
                                    <TextBlock Grid.Row="0" x:Name="NameTxt" TextWrapping="Wrap" Text="{Binding Name}" FontSize="28" Foreground="White"/> 
                                    <TextBlock Grid.Row="1" x:Name="AddrTxt"  TextWrapping="Wrap" Text="{Binding Address}" /> 
                                </Grid> 
                            </Border> 
                        </Grid> 
                    </DataTemplate> 
                </ListBox.ItemTemplate> 
            </ListBox> 
        </Grid>

Here Parent Grid(i.e ContentPanel) having two Rows ,in first row i placed the TextBox(i.e SearchTextBox)for entering search text.And  other hand in second row i placed ListBox control ,in  listbox DataTemplate i was taken Border inside Grid to make it as listboxitem having white border brush.And in Border there is two TextBlocks(NameTxt,AddrTxt) for binding Name & Address properties of 'Profile.cs' class

In c# we need to create class called 'Profile.cs' with properties 'Name &Address'.And make sure this properties should be match with binding objects names which we are earlier done in listbox datatemplate of above Xaml code .
C#

public class Profile : INotifyPropertyChanged 
    { 
        public string _name; 
        public string _addr; 
        public string Name 
        { 
            get { return _name; } 
            set { _name = value; NotifyPropertyChanged("Name"); } 
        } 
 
        public string Address 
        { 
            get { return _addr; } 
            set { _addr = value; NotifyPropertyChanged("Address"); } 
        } 
 
        public event PropertyChangedEventHandler PropertyChanged; 
        private void NotifyPropertyChanged(string property) 
        { 
            if (PropertyChanged != null) 
            { 
                PropertyChanged(thisnew PropertyChangedEventArgs(property)); 
            } 
        } 
    }
Take one ObservableCollection global object(i.e UserProfileList) for our 'Profile' class .And add some static items to list,finally bind that list to our ListBox(i.e listBoxobj).

C#

/**Creating ObservableCollections object to Profile.cs**/ 
ObservableCollection<Profile> UserProfileList = new ObservableCollection<Profile>(); 
/**Add some static items to above UserProfileList**/ 
 private void Listloading() 
        { 
            UserProfileList.Add(new Profile { Name = "Subbu", Address = "Hyderbad, India[441]" }); 
            UserProfileList.Add(new Profile { Name = "Raju", Address = "Hyd,India[91] " }); 
            UserProfileList.Add(new Profile { Name = "Sudhar", Address = " UK[44]" }); 
            UserProfileList.Add(new Profile { Name = "Sudhar Sharma", Address = "Bangalore" }); 
            UserProfileList.Add(new Profile { Name = "Navadeep", Address = "Mumbai" }); 
            UserProfileList.Add(new Profile { Name = "Anuroop", Address = "Pune" }); 
            UserProfileList.Add(new Profile { Name = "Kalyan", Address = "New Delhi" }); 
            UserProfileList.Add(new Profile { Name = "Venky", Address = "Kadapa" }); 
            UserProfileList.Add(new Profile { Name = "Sai", Address = "Canada" }); 
/**Finally bind list to our ListBox**/ 
listBoxobj.ItemsSource = UserProfileList; 
 
} 
Wow now we are done first step with very interestingly,so now lets go for second step.


2)How to implement listbox search functionality in windowsphone c#-xaml:


Now its time to filter listbox items based on text entered in SearchTextBox,so when text entering on the SearchTextBox we need to filter listbox items,thats why i taken 'TextChanged' event  of SearchTextBox.Because TextChanged event is fired when entered text is changed ,so this event is best fit for filtering listbox items.

C#

 bool LayoutUpdateFlag = true;//this is for handling layout upadated event 
private void contactFilterString_TextChanged(object sender, TextChangedEventArgs e) 
        { 
           //filter items with help of lambda expression 
            this.listBoxobj.ItemsSource = UserProfileList.Where(w => w.Name.ToUpper().Contains(SearchTextBox.Text.ToUpper()) || w.Address.ToUpper().Contains(SearchTextBox.Text.ToUpper())); 
            LayoutUpdateFlag = true; 
            
        } 
Note: Here i am using the bool variable 'layourUpdateFlag' ,which is useful for handling listbox 'LayoutUpdated' event in further step 3.Now we are done search functionality.Lets go for most interesting step .


3)Highlight the search result from Listbox items c#:

This step is most interesting and as well as little bit complicated.but after completing this step,we would feel like 'how it is very easy?".Ok lets see :)
So first we need helper class(i.e SearchVisualTree) for finding child items from listboxitem ,and then dynamically  format the child items  with 'Orange' color(i.e using Run element)  based on search text using separate method(i.e HighlightText())

C#

/** This helper class is for finding listbox datatemplate control elements**/ 
private void SearchVisualTree(DependencyObject targetElement) 
        { 
 
            var count = VisualTreeHelper.GetChildrenCount(targetElement);//get count targeted dependecnyobject 
 
            for (int i = 0; i < count; i++) 
            { 
                var child = VisualTreeHelper.GetChild(targetElement, i);//detecting listboxitem child items 
                if (child is TextBlock) 
                { 
                    textBlock1 = (TextBlock)child; 
                    prevText = textBlock1.Text; 
                    if ((textBlock1.Name == "NameTxt" || textBlock1.Name == "AddrTxt") && textBlock1.Text.ToUpper().Contains(SearchTextBox.Text.ToUpper())) 
                    { 
                        HighlightText();//after finding textblock child item call method for highligh color 
                    } 
                } 
                else 
                { 
                    SearchVisualTree(child);//repeat method call until targeted dependency found child items 
                } 
            } 
        } 
 
/**This method is for highlight the search text**/ 
  private void HighlightText() 
        { 
            if (textBlock1 != null) 
            { 
                string text = textBlock1.Text.ToUpper(); 
                textBlock1.Text = text; 
                textBlock1.Inlines.Clear(); 
 
                int index = text.IndexOf(SearchTextBox.Text.ToUpper());//getting index of search text from listboxitem textblock 
                int lenth = SearchTextBox.Text.Length; 
 
                if (!(index < 0)) 
                { 
 
                    Run run = new Run() { Text = prevText.Substring(index, lenth) }; 
                    run.Foreground = new SolidColorBrush(Colors.Orange);//format search text color with orange 
                    textBlock1.Inlines.Add(new Run() { Text = prevText.Substring(0, index) }); 
                    textBlock1.Inlines.Add(run); 
                    textBlock1.Inlines.Add(new Run() { Text = prevText.Substring(index + lenth) }); 
                } 
            } 
        }
Finally we need to handle above method calls,so when listbox is updated by search text  then set 'LayoutUpdateFlag = true' and we need to highlight searchitems,so i taken the listbox 'LayoutUpdated' event and call the above helper class


C#

private void listBoxobj_LayoutUpdated(object sender, EventArgs e) 
        { 
            if (LayoutUpdateFlag) 
            { 
                SearchVisualTree(listBoxobj); 
            } 
            LayoutUpdateFlag = false; 
        }
So sweet,now we are done all above three steps :listbox databinding,listbox search & finally hilghlight the search result with sepecific color.

Source file at: ListboxSearchSample

Note: Please share your thoughts,what you think about this post,Is this post really helpful for you?otherwise it would be very happy ,if you have any thoughts for to implement this requirement in any another way?I always welcome if you drop comments on this post and it would be impressive.

Follow me always at  
Have a nice day by  :)

7 comments:

  1. Hi, in dropdown on click/select want to redirect another page with click/selected parameter passing... pls can you help out this.

    ReplyDelete
  2. Hi subbu. When I input about >25 data item (example: animal1 -> animal 25). Then results return do not highlight all item, some of item not highlight (animal 18->animal 25). I don't know why?. When i test about <=17 data item (example: animal1 -> animal 17) is not problem. You test again.
    Thanks!

    ReplyDelete
    Replies
    1. look forward to receiving your feedback.

      Delete
    2. This is due to non static nature of the listbox - it won't create all items at once. So all the items didn't fit into viewport (+ and pre-cache) won't be handled by SearchVisualTree.

      The better approach is to use TextBlock-based custom control, that will handle highlighting internally, without visualtree hacking.

      In xaml it would be something like this:

      Delete
    3. arrrrrhh. hate blogspot commenting system :)

      In xaml it would be something like this:
      < u:HighlightingTextBlock Text="{Binding Name}" HighlightText="{Binding Text, ElementName=SearchBox}" HighlightBrush="{StaticResource PhoneAccentBrush}" / >

      Delete
  3. How To Convert List-box to Generic List

    ReplyDelete
  4. how to generate row numbers inside listbox in WP 8.1

    ReplyDelete

Search Engine Submission - AddMe