Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

An easy to use WPF Autocomplete Textbox

0.00/5 (No votes)
10 Jul 2014 1  
An easy to use custom control basedon textbox that allows Autocomplete, compatible with WCF
 
 

Introduction

The intention of this article is to share with the community some code I have been working on the last month, to allow a simple Texbox to have custom autocomplete filters. The idea was inspired by GMail search function. This custom control needs to have all the following features I need for my project:

  • It has to be very easy to use, an needs to integrate with my project with the less code as posible.
  • It needs to be compatible with WCF. My idea was, like GMail, to create a Layered application so the filter function needs to be executed on server side, and then the result transmited over WCF channel.
  • It needs to filter custom data (could be from database or from a custom list) and search on multiple field, just like GMail does, and suggest similar results.
  • All the filtering needs to be done in asynchronic way, so I will use Reactive librarys.
  • It has to interact with keyboard and mouse.
  • It needs to force the user to choose one item from avaible list.
  • It has to be fully compatible with the MVVM template I'm ussing on my project.
  • It needs to inform the user that the filter is beeing applied, and when the filtering is done.
  • It needs to let the user to navigate througth the result list, and choose one item.
  • All the code, except the filtering code need to be encapsulated inside the custom control.
  • Watermark text support
  • Also I need to have the ability off selecting a default option inside viewmodel, and reflect it on the control.

I found several samples source code over the net, but none accomplish all the above points. I did not write the whole code. I base this project on this excelent article http://blog.petegoo.com/2011/11/22/building-an-auto-complete-control-with-reactive-extensions-rx/. I'm open for all kind of sugestions on how to make this code better.

Background

For some month, I have been working on the migration of an VB6 application to new technologies. After several weeks of surfing and searching the web, learning new technologies, I manage to start with my project. One problem I face is how to let the user choose an item from several tables. By instance I need to let user to choose a customer from customers table for a customer order. This needs to be done over a WCF channel. Normally i would fill a combobox on client's side with all the customers and let user choose one, but this is inefficient. The idea is to imput some data from user (at least three character) to help filter data and return possible matches to the final user.

Using the code

From XAML point of view, using the control is very simple:

<Window x:Class="TextBoxAutoCompleteTest.Window1"

xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation

xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml 

xmlns:ac="clr-namespace:WpfAutoComplete.Controls;assembly=WpfAutoComplete" 

Title="Autocomplete Text Box Project"  

Height="300" Width="300"> 

<Grid> 

<StackPanel> 

<Label Content="This is an Autocomplete Textbox" /> 

<ac:TextBoxAutoComplete Name="autoTxtBoxEng" 

SearchDataProvider="{Binding Path=MySearchProviderEng}"  

SelectedListBoxValue="{Binding Path=PhraseNumber, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"

WatermarkText="Type in filtering text here..."/>  </StackPanel>

</Grid>

</Window>

Some notes about the code:

  • SearchDataProvider Property is the class that will be used for data filtering. The class needs to implement ISearchDataProvider interface.
  • SelectedListBoxValue is optional and proint to the property on VM to be updated by the control.
  • WatermarkText is the text to be shown when no input is entered.

This is an example of a simple SearchDataProvider class, that use a dictionary as sample:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TextBoxAutoCompleteTest 
{
    class MyDataProviderEng : WpfAutoComplete.ISearchDataProvider
    {
        public WpfAutoComplete.SearchResult DoSearch(string searchTerm)
        {
            return new WpfAutoComplete.SearchResult
            {
                SearchTerm = searchTerm,
                Results = dict.Where(item => item.Value.ToUpperInvariant().Contains(searchTerm.ToUpperInvariant())).ToDictionary(v => v.Key, v => v.Value)                
            };
        }

        public WpfAutoComplete.SearchResult SearchByKey(object Key)
        {
            return new WpfAutoComplete.SearchResult
            {
                SearchTerm = null,
                Results = dict.Where(item => item.Key.ToString()==Key.ToString()).ToDictionary(v => v.Key, v => v.Value)
            };            
         }

        private readonly Dictionary<object, string> dict = new Dictionary<object, string> {
            { 1, "The badger knows something"},
            { 2, "Your head looks something like a pineapple"},
            { 3, "Crazy like a box of green frogs"},
            { 4, "The billiard table has green cloth"},
            { 5, "The sky is blue"},
            { 6, "We're going to need some golf shoes"},
            { 7, "This is going straight to the pool room"},
            { 8, "We're going to  Bonnie Doon"},
            { 9, "Spring forward - Fall back"},
            { 10, "Gerry had a plan which involved telling all"},
            { 11, "When is the summer coming"},
            { 12, "Take you time and tell me what you saw"},
            { 13, "All hands on deck"}
        };
    }
}

Its easy to adapt this code to use a WCF service to filter and return avaible options instead of a pre-defined dictionary. Look at this new implementation of ISearchDataProvider:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Ohmio.Client.DataProviders
{
    class DataProviderClientes : WpfAutoComplete.ISearchDataProvider
    {
        private OhmioService.OhmioServiceClient serviceClient =
            new OhmioService.OhmioServiceClient();                
        
        public WpfAutoComplete.SearchResult DoSearch(string searchTerm)
        {            
            return new WpfAutoComplete.SearchResult
            {
                SearchTerm = searchTerm,
                Results = (serviceClient.EnumClientes(searchTerm.ToUpperInvariant())).ToDictionary(x=>(object)x.Key , y=>y.Descripcion)              
            };
        }

        public WpfAutoComplete.SearchResult SearchByKey(object Key)
        {
            return new WpfAutoComplete.SearchResult
            {
                SearchTerm = null,
                Results = (serviceClient.EnumClientes(Key.ToString())).ToDictionary(v => (object)v.Key, v => v.Descripcion)
            };
        }            
    }
}

In this case, a WCF service is used wich have one method call EnumClientes. This method get one filter parameter, execute the filted over the database and then returns a List<object> that its transformed into a dictionary object.

Points of Interest

I learn a lot in the process of writting this code. There are still some bugs / missing features that are beyound my actual undestanding of this code, especially about reactive library:

  • The code use delays between keystrokes to start the filtering proccess. The idea behind that is to make the filtering proccess more efficient instead of execute the filter for each typed character. Some times the control stop responding (it won't execute the filter after text insertion). When it lost the focus and hit Delete or Backspace, it works again.
  • Validation: A red border is draw around the control when no option is selected. I didn't find the way to personalize an error message.
  • The color of the Watermark text is fixed to ligth gray. This is a problem when the background is dark.
  • Multi-select option is missing.

History

July 10 - 2014: First Version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here