Silverlight ListBox with text searching

Posted 17 December 2008  

My "TextSearchListBox" control for Silverlight derives from ListBox and enables the text searching capability that many of us have come to expect in applications. The experience is a great improvement over the standard ListBox, and was simple enough to build out this evening.

I've attached the complete project and source code and hope that you find it useful in your apps in one way or another.

What's the text search feature?

When you give the list box control focus and type a character, the first item with the matching case insensitive prefix appears and is selected. For example, in the sample application attached to this post, I clicked on the list box control to give it focus, and then typed the letter 'c':

Charlotte
Pressed "c", Charlotte is selected.

If you're looking at a list of a thousand items, like a music playlist, this can be a time-saver. But you can also continue typing quickly, and even use the backspace to make corrections.

If I had quickly typed the letter "o" right after first letter, it would highlight the city of Columbus:

Columbus
Press "c" and then quickly "o", Columbus is selected.

The control's searching logic is also able to intelligently handle repeated keypresses to move down the list. So, after typing either of the earlier samples, or just from the start, you can press the "d" key 5 times. It quickly will move the selection from Dallas all the way through to Detroit:

Detroit  
Press "d" 5 times to move through the other "d" words in the list box.

This is a great feature and it was relatively easy to implement, especially given the similarities to a typical auto complete control.

I'll be honest, before I joined Microsoft several years ago, I didn't know that you could type in a standard list box in a useful way. It's one of those hidden gems that I have used so many times since the insightful day I learned of the capability.

How the string value of an item is determined

The string value is figured out very differently than in WPF. Since ListBox supports rich data items, there's no easy way in Silverlight for the TextSearchListBox to know what the underlying text value is, and I didn't want to pollute the example with any kind of binding or display member path work.

Instead, the logic for this example is super simple: the ToString() operator is used for each item.

That means that if you use something like a standard business object, the text search won't really work out so well - the search algorithm would think that every item is the text "YourNamespace.YourBusinessObject", if YourBusinessObject was the CLR class. In the attached sample application, I've simply bound to a list of strings. If you don't own the object to be able to override the ToString method, you can wrap the items in a derived or adapter class.

If you've used the AutoCompleteBox control in the Silverlight Toolkit, you'll notice that this is slightly different. For the auto complete control, I wanted to provide the best experience for item-to-string conversions, so there is also an exposed IValueConverter property called "Converter" that is tried before the ToString fallback.

Using the control

Simply download the source code or drop the TextSearchListBox.cs file into your Silverlight application, update the namespace, and you're ready to go.

Here's the XAML for the sample application:

<UserControl x:Class="YourNamespace.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:YourNamespace"
    Width="315" Height="340">
    <Grid x:Name="LayoutRoot" Margin="5">
        <Border BorderBrush="#11999999" BorderThickness="1" CornerRadius="3">
            <Border BorderBrush="#22999999" BorderThickness="1" CornerRadius="3">
                <Border BorderBrush="#33999999" BorderThickness="1" CornerRadius="3">
                    <local:TextSearchListBox x:Name="listBox1" />
                </Border>
            </Border>
        </Border>
    </Grid>
</UserControl>

And the page code behind:

using System.Linq;
using System.Windows.Controls;
using Microsoft.Windows.Controls.Samples;

namespace YourNamespace
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
            Loaded += (s, e) => listBox1.ItemsSource = (from n in Airport.SampleAirports orderby n.City select n.City).Distinct();
        }
    }
}

Downloads

Looking for a similar text searching control? Download the Silverlight Toolkit December 2008 release and check out the AutoCompleteBox control - a text box that provides a rich drop-down with completion suggestions.

Implementation Notes

  • This is a simple example: no extra dependency properties have been defined.
  • This really only works with the standard keyboard keys, no IME or advanced character support.
  • Anywhere you have a ListBox, in theory you should be able to replace it with this sample control.
  • Text search in this example does not have an automation peer, so the capability is not accessible or automatable.
  • A nice improvement might be adding the IsTextSearchEnabled dependency property, similar to what WPF has defined on the ItemsControl, to turn this behavior on or off. Right now I assume that you always want the behavior if you use the derived control.
  • Since Silverlight doesn't expose TextInput events like WPF does, I did have to go a little hacky in determining what characters were being typed. But in my brief testing with this app, it is working quite well anyway!

Hope this helps! Let me know if you find this useful.

Jeff Wilcox is a Principal Software Engineer at Microsoft in the Open Source Programs Office, helping Microsoft scale to 10,000+ engineers using, contributing to and releasing open source.

comments powered by Disqus