Click here to Skip to main content
Click here to Skip to main content

Highlight Searched Text in WPF ListView

, 25 Jun 2012
Rate this:
Please Sign up or sign in to vote.
This is an alternative for "Highlight Searched Text in WPF ListView"

Introduction 

An alternative implementation of 's article located here: Highlight-Searched-Text-in-WPF-ListView

This is how to filter + sort thousands of items while also highlighting text which matches your search phrase while also utilizing virtualization so that WPF programs don't run poorer then usual.   

New in this nearly 100% original and rewritten variation is: 

  • The ability to search and filter out items that don't match. 
  • The ability to sort the items by clicking the column header of the listview. 
  • A highly efficient implementation that does not rely on recursion to apply the highlighting effect. 
  • An example of a "WPF Custom Control Class Library"!! (all you need to know is it's just a regular class library, but you need to configure its AssemblyInfo.cs and have a "Themes" folder with a "Generic.xaml" to make it work). 

Using the code 

The program is very simple to use. Simply type some text into the search box and the number of items which are available to the listview for viewing will be limited so only those items which contain your search request will be visible. In addition you can click the "First Name" and "Last Name" columns to sort the items.

The HighlightTextBox control that was created for this project is also highly reusable for other applications so it's worthwhile to get acquainted with its simple design and use: 

To use this control, simply specify what you want to highlight with the HighlightPhrase property and if this string fragment is contained in the Text property then it will be highlighted using the HighlightBrush

This control was used in the DataTemplate's of the listview to define how to handle the rendering of listview items dynamically. Here is a minimal representation of the actual XAML: 

<ListView Name="listView"
          VirtualizingStackPanel.IsVirtualizing="True"
          VirtualizingStackPanel.VirtualizationMode="Recycling">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="200">
                <GridViewColumnHeader Content="First Name" />
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <controls:HighlightTextBlock Text="{Binding Path=FirstName}" 
                           HighlightPhrase="{Binding ElementName=textBoxSearch, Path=Text}" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Width="200">
                <GridViewColumnHeader Content="Last Name" />
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <controls:HighlightTextBlock Text="{Binding Path=LastName}" 
                           HighlightPhrase="{Binding ElementName=textBoxSearch, Path=Text}" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>   
</ListView>

Points of Interest

One thing I learned while writing this code is potentially the solution to this problem: WPF ListBox VirtualizingStackPanel.VirtualizationMode=“Recycling” causes same list items to always appear when scrolling.

Now I didn't encounter the exact same issue, but I did encounter similar behavior, i.e. setting the virtualization mode to standard stops the problem (but hurts performance) and it only happens when scrolling. In my version of the problem the highlighting wasn't showing up when you rapidly scrolled through items, but for the items that you could see when you first typed in the search box it worked perfectly. 

The solution was overloading the "Text" and "TextProperty" of HighlightTextBox and setting a PropertyChangedCallback which caused the highlighting to be re-applied when the text is changed (i know, this seems like a nobrainer now because the lack of this code is definitely a bug because you need to update the highlighting if the text changes just as much as you need to update it if the highlight phrase changes, but it's amazing how far I got with what seemed like otherwise perfect code to only see the problem when scrolling in recycling-virtualization mode).

The reason the new "Text" property fixes the problem is because when you scroll, while in recycling-virtualization mode, the existing instances of HighlightTextBox's are getting their Text property set, and perhaps i was expecting the HighlightPhrase property to also get set but that only actually happens (as per my binding in MainWindow.xaml) when you type in that search textbox.  

So to summarize: If you have any issues in recycling mode, it's the control you use in your DataTemplate that needs fixing. 

History 

  • June 25th 2010 : Fixed bug. Also cleaned up the code + added a way to see the virtualization in action, i.e. more detailed information in the window title.
  • June 24th 2012 : Initial post.  

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

FocusedWolf

United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 4 PinmemberOctopus11262-Jul-13 10:08 
BugHighlight has always the default color Pinmembercapibara25-Jun-12 3:25 
GeneralRe: Highlight has always the default color [modified] PinmemberFocusedWolf25-Jun-12 9:42 
What's wrong with always using yellow? Poke tongue | ;-P
 
Anyway thx i updated the article (and tested!) a fix based on your code.
 
The new UpdateHighlighting(...) function is now:
 
        private delegate void ApplyHighlightDelegate(HighlightTextBlock highlightTextBlock);
        private static ApplyHighlightDelegate action = ApplyHighlight;
 
        private static void UpdateHighlighting(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HighlightTextBlock tb = d as HighlightTextBlock;
 
            tb.Dispatcher.BeginInvoke(action, DispatcherPriority.Render, tb);
        }

 
Wait, yes although your fix does work, this is better: i forgot to set up a PropertyChangedCallback for the HighlightBrush property ::facepalm::
 
This works:
public static readonly DependencyProperty HighlightBrushProperty =
            DependencyProperty.Register("HighlightBrush", typeof(Brush),
            typeof(HighlightTextBlock), new FrameworkPropertyMetadata(Brushes.Yellow, FrameworkPropertyMetadataOptions.AffectsRender,
                new PropertyChangedCallback(UpdateHighlighting)));
 
Also IsCaseSensitiveProperty is missing the PropertyChangedCallback so it should be:
 
public static readonly DependencyProperty IsCaseSensitiveProperty =
            DependencyProperty.Register("IsCaseSensitive", typeof(bool),
            typeof(HighlightTextBlock), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender,
                new PropertyChangedCallback(UpdateHighlighting)));


modified 25-Jun-12 18:23pm.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 25 Jun 2012
Article Copyright 2012 by FocusedWolf
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid