5 January 2009
The default text filter used in the AutoCompleteBox control works well in most situations. I'd like to share an improvement that adds search engine-like "AND" operator support.
In this short guide, we'll change the text filter to support search strings like "b gates" matching to "bill gates" by splitting the search words and using them as independent lookups.
This example contains Visual Basic code that should be easily translatable to C#.
The default filter in AutoCompleteBox is a text filter that returns a value indicating whether the string is a suggestion. It is a "StartsWith" check, and uses the current culture for its comparison.
When you set or change the SearchMode dependency property on AutoCompleteBox, most SearchMode values will change the TextFilter property to one of the built-in filters - this happens behind the scenes.
You can set the TextFilter property to your own text-based algorithm or code to improve the experience, if you change the SearchMode to Custom.
For partial word matches, the idea is that the search string is split up into multiple words, each then used with an AND operator to determine matches.
The default filter understands spaces as literal characters, so a search for "microsoft silverlight" will literally only match a string that starts with "microsoft silverlight". Ideally, the text filter would let "soft silver" match the item text "microsoft silverlight".
These examples all set the TextFilter value of an auto complete instance in the Loaded event of the Silverlight Application's page.
These assume that you've already created your Silverlight Application project in Visual Studio, added a reference to the toolkit's Microsoft.Windows.Controls.dll library, added the xmlns "controls" to the page, and included an auto complete box control instance named "autoComplete1".
Define the word-splitting text filter:
' Splits the search string into words and returns true if the value contains ' them all. Function SplitWords(ByVal search As String, ByVal value As String) Dim words() As String value = value.ToLower words = search.Split(" ", StringSplitOptions.RemoveEmptyEntries) If words.Length = 0 Then Return False For Each searchWord As String In words searchWord = searchWord.ToLower If Not value.Contains(searchWord) Then Return False End If Next Return True End Function
During page load, setup the text filter (also adds some sample data):
Sub OnLoaded(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Loaded autoComplete1.SearchMode = AutoCompleteSearchMode.Custom autoComplete1.TextFilter = AddressOf SplitWords Dim list As New List(Of String) list.Add("Steve Ballmer") list.Add("Bill Gates") autoComplete1.ItemsSource = list End Sub
Here's the SplitWords function, updated to instead match any of the words in the search string, instead of them all:
' Splits the search string into words and returns true if the value contains ' at least one of them. Different from the first sample. Function AnySplitWord(ByVal search As String, ByVal value As String) Dim words() As String value = value.ToLower words = search.Split(" ", StringSplitOptions.RemoveEmptyEntries) If words.Length = 0 Then Return False For Each searchWord As String In words searchWord = searchWord.ToLower ' At least one was found! If value.Contains(searchWord) Then Return True End If Next ' None were matched Return False End Function
TextFilter takes a method or delegate that takes in two parameters: the search string, and the current item's text value. The item's text value is found by either using the optional Converter parameters on the control, or it will simply fall back to calling the ToString() method on the object. It returns a bool value indicating whether it is in the search.
The alternative ItemFilter is similar, but does not operate on string values for individual items. Instead, the 2nd parameter is a object type and represents the bound business object itself. The filter should return true when the item should be considered a suggestion.
If, and only if, you set the SearchMode to 'Custom', will the alternative ItemFilter property be used for determining suggestions.
In most apps, ItemFilter is your best bet for sophisticated business object lookups and decisions.
Hope this helps.
Jeff Wilcox is a Principal Software Engineer at Microsoft in the Open Source Programs Office, helping Microsoft scale to 15,000+ engineers using, contributing to and releasing open source.