How to: Change the Appearance and Behavior of the AutoCompleteBox Control
Microsoft Silverlight will reach end of support after October 2021. Learn more.
The AutoCompleteBox control is highly customizable in appearance and behavior. This topic shows you how to change the appearance and behavior of the AutoCompleteBox by setting its properties, handling events, and calling methods on the control. For information about how to perform advanced customization of the AutoCompleteBox's appearance and behavior by creating a new default template, see Control Customization and AutoCompleteBox Styles and Templates.
This topic contains the following sections:
Changing the appearance of the AutoCompleteBox
Changing how the AutoCompleteBox filters items
Populating the AutoCompleteBox Drop-Down Manually
Changing the appearance of the AutoCompleteBox
The AutoCompleteBox enables you to change its appearance by creating new styles.
To change the appearance of the text box part of the control
Create a style that targets the TextBox type and set the TextBoxStyle property to the style. The following XAML shows a style declared as a resource and set as the value for the TextBoxStyle property.
<Style x:Key="myTBStyle" TargetType="TextBox"> <Setter Property="Background" Value="LightYellow" /> <Setter Property="Foreground" Value="DarkSlateGray" /> <Setter Property="Margin" Value="5" /> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="FontSize" Value="14" /> <Setter Property="BorderBrush" Value="DarkGray" /> </Style> ... <sdk:AutoCompleteBox Width="150" Height="30" x:Name="myACB" TextBoxStyle="{StaticResource myTBStyle}" ItemContainerStyle="{StaticResource myLBStyle}" />
To change the drop-down part of the control
Create a style that targets the ListBox type and set the ItemContainerStyle property to the style. The following XAML shows a style declared as a resource and set as the value for the ItemContainerStyle property.
<Style x:Key="myLBStyle" TargetType="ListBoxItem"> <Setter Property="Background" Value="Khaki" /> <Setter Property="Foreground" Value="DarkSlateGray" /> <Setter Property="Margin" Value="5" /> <Setter Property="FontStyle" Value="Italic" /> <Setter Property="FontSize" Value="14" /> <Setter Property="BorderBrush" Value="DarkGray" /> </Style> ... <sdk:AutoCompleteBox Width="150" Height="30" x:Name="myACB" TextBoxStyle="{StaticResource myTBStyle}" ItemContainerStyle="{StaticResource myLBStyle}" />
Changing how the AutoCompleteBox filters items
You can specify how the AutoCompleteBox filters items. For example, you can specify whether it looks for matches at the start of a word, in a word, or other choices. You may also need a custom text or object filter for the objects displayed in the AutoCompleteBox, but you are not able to change the object. In this case, you can create a custom text or object filter for the AutoCompleteBox by setting the TextFilter or ItemFilter properties to a method that matches the signature of the AutoCompleteFilterPredicate<T> delegate.
To change how the AutoCompleteBox filters items
Set the FilterMode property to a AutoCompleteFilterMode value.
The following XAML shows how to set the FilterMode property to look for a string that contains another string and is case sensitive.
<input:AutoCompleteBox FilterMode="ContainsCaseSensitive" Height="40" Width="200" x:Name="ACB" />
To create a custom string filter
Set the TextFilter property to a method that matches the signature of the AutoCompleteFilterPredicate<T> delegate type that accepts a string. The method should perform the necessary string filtering for your AutoCompleteBox.
The following example code shows associating the property with the delegate method, and the custom string filtering.
Private employees As New List(Of Employee)() Public Sub New() InitializeComponent() ' Add some items to the employee list. employees.Add(New Employee("Sells", "Chris", "csells", 1234)) employees.Add(New Employee("Cabatana", "Reina", "rcaba", 5678)) employees.Add(New Employee("Sprenger", "Christof", "cspreng", 9123)) employees.Add(New Employee("Brandel", "Jonas", "jbrandel", 4567)) employees.Add(New Employee("Bye", "Dennis", "dbye", 8912)) employees.Add(New Employee("Reid", "Miles", "mreid", 3456)) ' Set the item source. myACB.ItemsSource = employees ... ' Set the TextFilter property to the search method. myACB.TextFilter = AddressOf SearchEmployees ... End Sub ... Private Function SearchEmployees(ByVal search As String, ByVal value As String) As Boolean value = value.ToLower() ' Split the string a new line. Dim words As String() = value.Split(System.Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries) Dim names As String() = words(0).Split(" "c) ' Look for a match in the first line; discarding the "employee:" entry. For Each name As String In names If name <> "employee:" Then If name.StartsWith(search) Then Return True End If End If Next ' If no match, return false. Return False End Function ... Public Class Employee Private _LastName As String Public Property LastName() As String Get Return _LastName End Get Set(ByVal value As String) _LastName = value End Set End Property Private _FirstName As String Public Property FirstName() As String Get Return _FirstName End Get Set(ByVal value As String) _FirstName = value End Set End Property Private _EmailName As String Public Property EmailName() As String Get Return _EmailName End Get Set(ByVal value As String) _EmailName = value End Set End Property Private _ID As Integer Public Property ID() As Integer Get Return _ID End Get Set(ByVal value As Integer) _ID = value End Set End Property Public Sub New(ByVal empLastName As String, ByVal empFirstName As String, ByVal empEmail As String, ByVal empID As Integer) LastName = empLastName FirstName = empFirstName EmailName = empEmail ID = empID End Sub Public Overloads Overrides Function ToString() As String Return ((("Employee: " & FirstName & " ") + LastName + System.Environment.NewLine & "Email: ") + EmailName + System.Environment.NewLine & "ID: ") + ID.ToString() End Function End Class
List<Employee> employees = new List<Employee>(); public MainPage() { InitializeComponent(); // Add some items to the employee list. employees.Add(new Employee("Sells", "Chris", "csells", 1234)); employees.Add(new Employee("Cabatana", "Reina", "rcaba", 5678)); employees.Add(new Employee("Sprenger", "Christof", "cspreng", 9123)); employees.Add(new Employee("Brandel", "Jonas", "jbrandel", 4567)); employees.Add(new Employee("Bye", "Dennis", "dbye", 8912)); employees.Add(new Employee("Reid", "Miles", "mreid", 3456)); // Set the item source. myACB.ItemsSource = employees; ... // Set the TextFilter property to the search method. myACB.TextFilter += SearchEmployees; ... } ... bool SearchEmployees(string search, string value) { value = value.ToLower(); // Split the string a new line. string[] words = value.Split(System.Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); string[] names = words[0].Split(' '); // Look for a match in the first line; discarding the "employee:" entry. foreach (string name in names) { if (name != "employee:") if (name.StartsWith(search)) return true; } // If no match, return false. return false; } ... public class Employee { public string LastName { get; set; } public string FirstName { get; set; } public string EmailName { get; set; } public int ID { get; set; } public Employee(string empLastName, string empFirstName, string empEmail, int empID) { LastName = empLastName; FirstName = empFirstName; EmailName = empEmail; ID = empID; } public override string ToString() { return "Employee: " + FirstName + " " + LastName + System.Environment.NewLine + "Email: " + EmailName + System.Environment.NewLine + "ID: " + ID.ToString(); } }
<StackPanel x:Name="LayoutRoot" Background="LightGray"> <TextBlock FontWeight="Bold" Text="AutoCompleteBox Custom Filter Example" Margin="5"/> <StackPanel Orientation="Horizontal"> <TextBlock Text="Employee:" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Center"/> <sdk:AutoCompleteBox Height="75" Width="200" VerticalAlignment="Center" HorizontalAlignment="Right" x:Name="myACB" FilterMode="Custom" ToolTipService.ToolTip="Enter employee name."/> </StackPanel> </StackPanel>
To create a custom object filter
Set the ItemFilter property to a method that matches the signature of the AutoCompleteFilterPredicate<T> delegate type that accepts a object. The method should perform the necessary object filtering for your AutoCompleteBox.
The following code shows an example of setting the ItemFilter property and the custom object filtering.
Private employees As New List(Of Employee)() Public Sub New() InitializeComponent() ' Add some items to the employee list. employees.Add(New Employee("Sells", "Chris", "csells", 1234)) employees.Add(New Employee("Cabatana", "Reina", "rcaba", 5678)) employees.Add(New Employee("Sprenger", "Christof", "cspreng", 9123)) employees.Add(New Employee("Brandel", "Jonas", "jbrandel", 4567)) employees.Add(New Employee("Bye", "Dennis", "dbye", 8912)) employees.Add(New Employee("Reid", "Miles", "mreid", 3456)) ' Set the item source. myACB.ItemsSource = employees ... ' Set the ItemFilter property to the search method. myACB.ItemFilter = AddressOf SearchEmployees ... End Sub ... Private Function SearchEmployees(ByVal search As String, ByVal value As Object) As Boolean ' Cast the value to an Employee. Dim emp As Employee = TryCast(value, Employee) If emp IsNot Nothing Then ' Look for a match in the first and last names. If emp.LastName.ToLower().StartsWith(search) Then Return True ElseIf emp.FirstName.ToLower().StartsWith(search) Then Return True End If End If ' If no match, return false. Return False End Function ... Public Class Employee Private _LastName As String Public Property LastName() As String Get Return _LastName End Get Set(ByVal value As String) _LastName = value End Set End Property Private _FirstName As String Public Property FirstName() As String Get Return _FirstName End Get Set(ByVal value As String) _FirstName = value End Set End Property Private _EmailName As String Public Property EmailName() As String Get Return _EmailName End Get Set(ByVal value As String) _EmailName = value End Set End Property Private _ID As Integer Public Property ID() As Integer Get Return _ID End Get Set(ByVal value As Integer) _ID = value End Set End Property Public Sub New(ByVal empLastName As String, ByVal empFirstName As String, ByVal empEmail As String, ByVal empID As Integer) LastName = empLastName FirstName = empFirstName EmailName = empEmail ID = empID End Sub Public Overloads Overrides Function ToString() As String Return ((("Employee: " & FirstName & " ") + LastName + System.Environment.NewLine & "Email: ") + EmailName + System.Environment.NewLine & "ID: ") + ID.ToString() End Function End Class
List<Employee> employees = new List<Employee>(); public MainPage() { InitializeComponent(); // Add some items to the employee list. employees.Add(new Employee("Sells", "Chris", "csells", 1234)); employees.Add(new Employee("Cabatana", "Reina", "rcaba", 5678)); employees.Add(new Employee("Sprenger", "Christof", "cspreng", 9123)); employees.Add(new Employee("Brandel", "Jonas", "jbrandel", 4567)); employees.Add(new Employee("Bye", "Dennis", "dbye", 8912)); employees.Add(new Employee("Reid", "Miles", "mreid", 3456)); // Set the item source. myACB.ItemsSource = employees; ... // Set the ItemFilter property to the search method. myACB.ItemFilter += SearchEmployees; ... } ... bool SearchEmployees(string search, object value) { // Cast the value to an Employee. Employee emp = value as Employee; if (emp != null) { // Look for a match in the first and last names. if (emp.LastName.ToLower().StartsWith(search)) return true; else if (emp.FirstName.ToLower().StartsWith(search)) return true; } // If no match, return false. return false; } ... public class Employee { public string LastName { get; set; } public string FirstName { get; set; } public string EmailName { get; set; } public int ID { get; set; } public Employee(string empLastName, string empFirstName, string empEmail, int empID) { LastName = empLastName; FirstName = empFirstName; EmailName = empEmail; ID = empID; } public override string ToString() { return "Employee: " + FirstName + " " + LastName + System.Environment.NewLine + "Email: " + EmailName + System.Environment.NewLine + "ID: " + ID.ToString(); } }
<StackPanel x:Name="LayoutRoot" Background="LightGray"> <TextBlock FontWeight="Bold" Text="AutoCompleteBox Custom Filter Example" Margin="5"/> <StackPanel Orientation="Horizontal"> <TextBlock Text="Employee:" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Center"/> <sdk:AutoCompleteBox Height="75" Width="200" VerticalAlignment="Center" HorizontalAlignment="Right" x:Name="myACB" FilterMode="Custom" ToolTipService.ToolTip="Enter employee name."/> </StackPanel> </StackPanel>
Populating the AutoCompleteBox Drop-Down Manually
You may want to populate the AutoCompleteBox with the result of an asynchronous call to a Web service, or other data source, and therefore populate the drop-down manually. You can easily override the default filtering behavior of the AutoCompleteBox to do this.
To populate the AutoCompleteBox drop-down manually
Optionally, set the MinimumPopulateDelay to 100 or more to delay the populate operation. This decreases the number of calls to populate the AutoCompleteBox as the user types.
Optionally set the MinimumPrefixLength to a value greater than 1 to decrease the number of calls to the populate operation.
Handle the Populating event and cancel it by setting the PopulatingEventArgs.Cancel property to true. This notifies the control that you will populate it manually.
Call the method that will perform the filtering operation. If you are calling a Web service, this will involve a callback method. In this method, when the filter operation is complete, call PopulateComplete. This notifies the control that you are finished populating the control.
The following code shows how to set MinimumPopulateDelay an MinimumPrefixLength properties handle the Populating event, and call PopulateComplete when the operation is finished. The code calls a Web service asynchronously and uses the returned XML to populate the AutoCompleteBox.
<StackPanel x:Name="LayoutRoot" Background="White" Orientation="Horizontal"> <TextBlock Text="News Topic:" HorizontalAlignment="Left" VerticalAlignment="Center"/> <sdk:AutoCompleteBox VerticalAlignment="Center" HorizontalAlignment="Right" Height="30" Width="100" MinimumPopulateDelay="200" MinimumPrefixLength="3" x:Name="myACB" Populating="AutoCompleteBox_Populating" /> </StackPanel>
' Handle the Populating event, but cancel it. Make the call to the web service. Private Sub AutoCompleteBox_Populating(ByVal sender As Object, ByVal e As PopulatingEventArgs) e.Cancel = True CallToWebService() End Sub ' Call the topic service at the live search site. Private wc As WebClient Private Sub CallToWebService() wc = New WebClient() wc.DownloadStringAsync(New Uri("http://api.search.live.net/qson.aspx?query=" & _ myACB.SearchText & "&sources=news")) AddHandler wc.DownloadStringCompleted, AddressOf wc_DownloadStringCompleted End Sub Private Sub wc_DownloadStringCompleted(ByVal sender As Object, _ ByVal e As DownloadStringCompletedEventArgs) If e.[Error] IsNot Nothing Then Exit Sub End If Dim data As New List(Of String)() Try Dim jso As JsonObject = TryCast(DirectCast(JsonObject.Parse(e.Result), _ JsonObject)("SearchSuggestion"), JsonObject) Dim originalSearchString As String = jso("Query") If originalSearchString = myACB.SearchText Then For Each suggestion As JsonObject In DirectCast(jso("Section"), JsonArray) data.Add(suggestion.Values.First()) Next ' Diplay the AutoCompleteBox drop down with any suggestions myACB.ItemsSource = data myACB.PopulateComplete() End If Catch End Try End Sub End Class
// Handle the Populating event, but cancel it. Make the call to the web service. private void AutoCompleteBox_Populating(object sender, PopulatingEventArgs e) { e.Cancel = true; CallToWebService(); } // Call the topic service at the live search site. WebClient wc; private void CallToWebService() { wc = new WebClient(); wc.DownloadStringAsync(new Uri ("http://api.search.live.net/qson.aspx?query=" + myACB.SearchText + "&sources=news")); wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted); } void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { if (e.Error != null) { return; } List<string> data = new List<string>(); try { JsonObject jso = ((JsonObject)JsonObject.Parse(e.Result)) ["SearchSuggestion"] as JsonObject; string originalSearchString = jso["Query"]; if (originalSearchString == myACB.SearchText) { foreach (JsonObject suggestion in (JsonArray)jso["Section"]) { data.Add(suggestion.Values.First()); } // Diplay the AutoCompleteBox drop down with any suggestions myACB.ItemsSource = data; myACB.PopulateComplete(); } } catch { } } }