Filtering List Boxes with a Little Help from XAML

Information equals data plus context, and at this point in mankind's history, we have way too much data. But there are ways to constrain it all and make it usable, including through software. Consider the Web site Google.com -- perhaps you've heard of it. Despite having its fingers in billions of Web pages, it can filter them down pretty quickly as you type, showing you the most likely matches for whatever you've entered so far.

Such filtering isn't limited to the World Wide Web; you can use such features in your own XAML app. The example presented here displays a list of American cities, allowing the user to see a subset of choices by typing a filtering text value. The code will apply that filter to both the city name and one or more ZIP codes included in each town's jurisdiction. Figure 1 shows the running program, with a city displayed based on a partial ZIP code value.

Figure 1: A Filtered List Box

Naturally, the first step is to figure out how to identify matching cities from the text pattern. Create a new WPF App (.NET Framework) in C#, and add a new interface file called ITextFilter.cs. It will define a single member, a method that indicates whether an object is a match for a supplied string pattern:

interface ITextFilter
{
bool IsMatch(string pattern);
}

Next, create the class that will contain each city name and associated ZIP codes. Add a class file named CityEntry.cs to the project, and apply the ITextFilter interface to its definition. The class will include two public members: a city name, and a collection of ZIP codes, each stored as a numeric string:

That's it for the individual data objects. Next, create the class that will host the collection of city objects, and present them to the display form. Add a new class file to the project called CityData.cs, and apply the INotifyPropertyChanged interface to enable XAML data binding:

The class exposes two public properties for binding, one for the list of cities, and one to set the filter pattern. I won't bore you with all of the boilerplate view-notification code -- download the sample project for this article to see those details -- but here is how the two properties will look to any user of a CityData instance:

The constructor for CityData builds the list of cities and ZIP codes and stores them in a private collection called AllCities. Those objects are then dumped into MatchingCities, since in the absence of a filter pattern all records should appear:

That completes the back-end code. The only thing left to do is to craft the code for the form. And it turns out that there's no code to write, because everything that’s still needed will appear in XAML. I'm convinced that XAML was invented by Microsoft programmers who wanted to get out of the tedium of developing UI code. But whatever the reason, the following XAML markup, when used to replace the default tag in the MainWindow.xaml content, will connect the form up to a CityData instance:

The markup adds a list box to the form, connecting it to the exposed MatchingCities collection. It also includes a text box control, with a two-way connection to the Filter property. Instantiating the source data through the <Window.DataContext> tag has one side benefit, that of showing the list of cities while in design mode.

Run the program and type either a partial city name or a partial ZIP code into the text box. As you type, the selection of cities will adjust itself to just those that match the criteria. The sample project includes less than 100 ZIP codes and related cities, so the display updates quickly. If you had a system with, say, billions of Web sites behind the filter, you might want to make some minor adjustments to the code to speed things up.

Tim Patrick has spent more than thirty years as a software architect and developer. His two most recent books on .NET development -- Start-to-Finish Visual C# 2015, and Start-to-Finish Visual Basic 2015 -- are available from http://owanipress.com. He blogs regularly at http://wellreadman.com.