Click here to Skip to main content
Click here to Skip to main content

WPF Auto-complete Control

By , 14 Dec 2009
 

Introduction

There seems to be a lack of support for an auto-complete control in WPF. The closest one to it is the ComboBox which is the base of our implementation for this article.

Background

An auto-complete control is one that allows the user to enter text while querying for a possible selection based on what the user has already entered. The most popular auto-complete implementation deals with querying of a "Starts With" of the current text in the control.

How it Works

Here are some of the properties we care about in the ComboBox:

  • IsEditable- This allows the user to input text into the control.
  • StaysOpenOnEdit - This will force the combobox to stay open when typing.
  • IsTextSearchEnabled - This uses the default "auto-complete" behavior of the ComboBox.

The Magic

By using a combination of the above properties (pretty self-explanatory) and a timer to control the delay of the query, an event which allows the user to attach a new data source, and some styles, we could implement an auto-complete control.

Using the Control

XAML

<Window x:Class="Gui.TestWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ctr="clr-namespace:Gui.Controls"
      Title="Auto Complete Test" 
      Height="200" Width="300" 
      Loaded="Window_Loaded">
    <StackPanel>
        <StackPanel.Resources>
            <ResourceDictionary 
              Source="/Gui.Controls;component/Styles/AutoComplete.Styles.xaml" />
        </StackPanel.Resources>
        
        <Label>Cities:</Label>
        <ctr:AutoComplete x:Name="autoCities" 
           SelectedValuePath="CityID" DisplayMemberPath="Name" 
           PatternChanged="autoCities_PatternChanged" 
           Style="{StaticResource AutoCompleteComboBox}"
           Delay="500"/> 
        <!-- can also do binding on selected value -->
    </StackPanel>
</Window>

Similar to a combo box, an auto-complete control utilizes the DisplayMemberPath and SelectValuePath properties to bind to a specific data source.

Code-Behind

/// <summary>
/// occurs when the user stops typing after a delayed timespan
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
protected void autoCities_PatternChanged(object sender, 
          Gui.Controls.AutoComplete.AutoCompleteArgs args)
{
    //check
    if (string.IsNullOrEmpty(args.Pattern))
        args.CancelBinding = true;
    else
        args.DataSource = TestWindow.GetCities(args.Pattern);
}

We can utilize the PatternChanged event to subscribe to changes to the the data source. This data source is also equal to a pattern the user has currently entered into the control.

Points of Interest

We utilize the MVVM pattern to create a ViewModel of any entity bound to the data source which contains the HighLight property. Through the use of styles, this highlighted section will be reflected in the dropdown.

History

  • Dec. 14, 2009 - Initial creation.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Yang Yu
Architect Prognex Corp.
Canada Canada
Member
Love startups, programming, and machine learning.
 
CEO and Founder of FansFave.com
 
LinkedIn: http://www.linkedin.com/in/mryuyang
Twitter: http://twitter.com/mryangyu

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionusing in xceed datagrid controlmemberpiyu_nehal15 Apr '13 - 3:43 
Thankyou for the code,
control works brillient..
QuestionHow to bind to datamemberFrank Cazabon2 Jan '13 - 5:35 
Hi,
 
I'm trying to use this control and bind it to some data.
 
If it were a combo box I would set it up like this:
 
<ComboBox Name="cboCustomers" DisplayMemberPath="cus_number" SelectedValuePath="cus_pk" SelectedValue="{Binding inv_cusfk, Mode=Default}" />
 
If I try this with the autocomplete control I don't get the customer number displaying when viewing existing data:
 
<ctr:AutoComplete x:Name="autoCustomers" Grid.Row="3" Grid.Column="1" 
                                          SelectedValuePath="cus_pk" DisplayMemberPath="cus_number" 
                                          SelectedValue="{Binding inv_cusfk, Mode=Default}"
                          PatternChanged="autoCustomers_PatternChanged" 
                          Delay="500" LostFocus="autoCustomers_LostFocus" />

QuestionPopulate with a value?membernyland25 Jan '12 - 10:30 
I am using your code and find it very useful. However I have a problem.
Next to the control I have a + button to open a new window for adding an item to the existing list. When I save the new item and close the window, I want the combobox to show that new value. It is not showing anything! I am sharing the same viewmodel for the combobox form and the new item form. In the vm I set the new value of the SelectedItem for the combobox and I do a RaisePropertyChanged. Other fields that uses the same SelectedItem gets updated but not this auto-complete combobox.
Would you know how to fix this?
 
Thanks in advance.
QuestionConverting to VBmemberchj12424 Jun '11 - 8:19 
i have been trying to convert this sample to VB but have not been having some problems.
 
do you have a VB version, or can you provide one?
chj...
Wink | ;-)

GeneralMy vote of 5membernjdnjdnjdnjdnjd9 May '11 - 22:44 
Perfect
GeneralMy vote of 1memberVolcano_881018 Nov '10 - 17:38 
Bad memory leaks, unusable. simply returns an array
GeneralGetting ItemsSource to workmembercjroebuck15 Dec '09 - 6:52 
Hi,
 
How can I get this to work as a combobox with initial ItemsSource where the user types and the ItemsSource is filtered down. At the moment the items are only revealed once the user types something.
 
Thanks
GeneralRe: Getting ItemsSource to workmemberYang Yu15 Dec '09 - 7:29 
Good question. This implementation is a straight forward and focuses on the "easy to understand" aspect.
 
You could however create a ViewModel wrapper to wrap any entity and provide additional properties such as IsMatch, Accuracy. Then in the ItemTemplate Style of the combobox, set it to an DataTemplate that deals with this ViewModel with a trigger and bind the IsVisible property to the IsMatch.
 
Alternatively you can create an ObservableCollection that will be responsible for overriding the Items property to exclude the non matching items, and provide a Filter(string pattern) method on the collection, then invoke this method on the PatternChanged event.
 
hope this helps. When I have sometime, I will go back to add these functionalties into this article along with the highlight feature.
 
cheers.
yang
 
Yang Yu
Prognex Corp.
www.prognex.com

GeneralThanks a lot!memberRatish Philip14 Dec '09 - 23:46 
This is what I was looking for. Thanks a lot!
I voted with a 5.
 
Ratish Philip

GeneralRe: Thanks a lot!memberYang Yu15 Dec '09 - 11:06 
your welcome Smile | :) appreciate the comment.
 
Yang Yu
Prognex Corp.
www.prognex.com

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 14 Dec 2009
Article Copyright 2009 by Yang Yu
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid