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

  1. 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.

  2. Optionally set the MinimumPrefixLength to a value greater than 1 to decrease the number of calls to the populate operation.

  3. 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.

  4. 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 { }
        }
    }