Latest Tweet:
  • Loading...

This blog post is one of three I’m posting to introducing some of the new features in the Silverlight Toolkit announced today at the PDC 2008. For more information about and downloads of the toolkit check out
http://www.codeplex.com/Silverlight.

Auto complete textboxes have become a common interaction model in both web and desktop applications. All the modern browsers have smart suggestions directly in the address bar. E-mail clients on the web and on your desktop will try to suggest the recipient by looking in your address book as you type. Leveraging auto complete in your application is a great way to improve the user experience by limiting errors and cutting down the amount of typing needed to complete a form.

One of the new controls in the Silverlight Toolkit is the AutoCompleteBox control, and in this post I’m going to show how to implement auto completion it in the Dive Log application. The AutoCompleteBox control supports both data bound suggestions as well as custom code to get suggestions asynchronously, for instance by calling a web service. I will cover both scenarios and show how the auto completion code fits in to the Model-View-ViewModel architecture of the Dive Log application.

The AutoCompleteBox control looks and feels like a textbox, and has a Text-property. This makes it easy to upgrade any existing application that uses textboxes to use the AutoCompleteBox control instead. In the Dive Log application I’m going to upgrade the location and buddy textboxes to AutoCompleteBox controls. The auto complete suggestions for dive buddy will be data bound to local values, while the suggestions for dive location will be retrieved from the Dive Log web service.

TextBoxes that needs AutoComplete

Data Bound Auto Complete Suggestions

For safety reasons you never dive alone and always have a buddy with you. There is a good chance you will do multiple dives with the same diver, and having to type in the full name every time you log a new dive can be bothersome. To improve the user experience I’m going to replace the textbox with the AutoCompleteBox control. The suggested values for auto completion are going to be a list of all the buddies the user previously has dived with. If this is the first time with a new buddy the user simply types in the name as in any textbox, and for the next dive this name will be included in the auto complete text box.

The Dive Log application uses the Model-View-ViewModel pattern to keep things nice and separated. All UI components on screen are data bound against properties on the ViewModel. One of the properties is a list of all the logged dives for the currently logged on user. For the AutoCompleteBox control we need to expose a new property returning a list of all dive buddies. This is implemented as a simple LINQ query. The ViewModel implements the INotifyPropertyChanged interface, so every time the list of dives changes we need to fire the event to signal that the list of Buddies has changed.

Property exposed by ViewModel with suggestions.

Now that we have prepared the ViewModel with this new property we can replace the buddy textbox with the AutoCompleteBox control. The AutoCompleteBox control has a Text-property just like the textbox. The name of the buddy for the selected dive is two-way data bound against the Text-property on the AutoCompleteBox control. The AutoCompleteBox has an ItemsSource-property that we bind against the new Buddies-property on the ViewModel.

Buddy TextBox replaced with AutoCompleteBox 

When we run the application and start typing the name of our dive buddy the AutoCompleteBox control will make suggestions based on the values in the data bound list. I haven’t applied any styling to the control, so that the moment the UI looks a little bit off. We will deal with that later.

AutoCompleteBox without styles applied

Auto Complete Suggestions from a web services

In some cases the list of possible matches is too big to be kept in memory and loaded when the application starts. Examples of this could be the Amazons book database or auto completion in an e-mail client where you have a shared address book with thousands of contacts. In these cases you need to query the server for auto complete suggestions as the user types to only get relevant suggestions. For the Dive Log application we’re going to implement code to call a web service to get suggestions for dive locations. There is a good chance that someone else have been to a location before you, so by querying the entire Dive Log database we can provide better auto complete suggestions, and at the same time save bandwidth as we don’t have to download everything at once.

To implement asynchronous suggestions in the AutoCompleteBox control you need to subscribe to the Populating-event of the control. This event will let you run code when the control is trying to populate the list of suggestions. In the event handler you need to set the Cancel-property on the event argument to false before calling your web service to get suggestions. The event argument also contains a Paramter-property holding whatever text the user has typed already. We pass this parameter to the web service to get dive locations that match the text the user have typed in.

AutoCompleteBox Populating Event Handler

I had some problems deciding where to put the code to populate the AutoCompleteBox control. The code needs to have a reference to the AutoCompleteBox control to hook the Populating-event, set the ItemsSource-property and call the PopulateComplete-method when the results are ready. The most obvious place to put this code is directly in the code behind of the page. However, I always try to keep the amount of code in View to an absolute minimum, so my second attempt was to put the code responsible for handling the event and calling the web service in a separate class. The class took the AutoCompleteBox control in the constructor to get a reference to the control. Then in code-behind I would simply instantiate the class and pass in the AutoCompleteBox control to wire things up. This is a better solution than having everything in code-behind, but I’m still not happy. The class responsible for managing auto complete suggestions also needs a reference to the web service client to get suggestions from the server, and to not break testability I want to provide this dependency in the constructor.

The solution I ended up with has a separate class responsible for managing auto complete suggestions, but the reference to the AutoCompleteBox control is set using a property instead of the constructor. In the setter the class will register the event listener for the Populating-event. The class also takes the IDiveServiceClient interface in the constructor so that I can use the Ninject IoC-container to create the object.

AutoCompleteBoxTarget property 

The final problem is how to set the AutoCompleteBox property saying which control the class is providing auto complete suggestions for. I implement an attached dependency property which allows me to use XAML to link the AutoCompleteBox control against the class responsible for managing auto complete suggestions. The implementation of the dependency property I similar to the Command-pattern implementation used in the Dive Log application. I’m not going to include the full implementation here, as the source code is available for download.

AutoCompleteBox AttachedProperty

The web service method returning suggestions is incredibly simple. It takes a prefix argument and runs a simple LINQ query getting all dive locations starting with that prefix.

GetLocations WebService Method

Styling the AutoCompleteBox

Styling the AutoCompleteBox to make it fit with the look and feel of the Dive Log application is really simple. If we use Expression Blend to edit a copy of the default control template we see that the core pieces of the AutoCompleteBox is a TextBox, a Popup and a ListBox. The Popup shows suggestions in the ListBox as the user types in the TextBox. So if you know how to style a TextBox and a ListBox you got the skills needed to style the AutoCompleteBox. I would recommend styling the ListBox independently, as you cannot see the suggestion ListBox in design mode.

Styling the AutoCompleteBox in Blend 2

Since the Dive Log application already have predefined styles for TextBoxes and ListBoxes it didn’t take long to make the AutoCompleteBox look just right. I simply had to apply the excising styles and tweak the border control around the ListBox to make it look nice.

AutoCompleteBox styled

Summary

The AutoCompleteBox control in the Silverlight Toolkit makes it really easy to enhance the user experience by providing auto complete behavior to your application. The control can easily replace excising textboxes where that makes sense. The control gives you the flexibility to use either data bound auto complete suggestions, or write custom code to access web services to get suggestions. The Dive Log application includes examples on how to do both. The Dive Log source code also contains an example of an attached dependency property that allows you to add asynchronous suggestions without cluttering your code-behind.
Tuesday, October 28, 2008 9:35:04 PM (W. Europe Standard Time, UTC+01:00)
You've just insulted Steve *Ballmer*. :)
Wednesday, October 29, 2008 7:28:07 PM (W. Europe Standard Time, UTC+01:00)
I like how do you added handwriting comments. It is much better to see as normal comments.

regards
Peter Loebel
Tuesday, November 04, 2008 7:59:38 PM (W. Europe Standard Time, UTC+01:00)
Jonas,

Just used this tutorial to implement the AutoCompleteBox in colaab...

Great to meet you at PDC, would have been good to get some more time to chat, but as I'm sure you saw - things went a bit mental!

Got some really good feedback and interesting leads, sending out follow up email this week so will keep you informed.

Thanks again,

Bob
Wednesday, November 05, 2008 4:59:29 AM (W. Europe Standard Time, UTC+01:00)
Bob,

Was great to meet you guys at PDC, and yeah, PDC was a bit mental at times! The week just passed all to quick.

It's great to hear that you made some good connections at PDC - and let me know if there is anything more I can do, people you want me to introduce you to etc.

Glad you found the post useful :)

I'm still recovering from post PDC stress, so will probably be back blogging later this week ;)

Cheers,
Jonas
Wednesday, November 19, 2008 2:44:21 PM (W. Europe Standard Time, UTC+01:00)

Very nice articles Jonas. I agree with Peter - I really like the hand written type comments.
Wednesday, January 28, 2009 5:45:48 PM (W. Europe Standard Time, UTC+01:00)
Hi excellent article however im a bit confused on how to attach the web service to the itemssource could you provide a link for the source code in this example? thanks
Keoz
Saturday, February 21, 2009 6:16:57 PM (W. Europe Standard Time, UTC+01:00)
its unique articles jonas...the comment style is also very attractive..
great..
Wednesday, March 04, 2009 3:11:33 PM (W. Europe Standard Time, UTC+01:00)
Jonas - please help :)

I have setup my application very similiar to this article, using a MVVM setup.

For whatever reason, the itemsource only populates when I set it in code behind directly.

When using my viewmodel it doesn't work for me?

To test the data coming back, I have a listbox that is validating I'm getting the items.

In my model:
public List<string> FilteredServiceList
{
get
{
return (from s in ServiceClients
select s.ServiceDescription).ToList();
}
}

<Controls:AutoCompleteBox x:Name="FilterCriteria"
ItemsSource="{Binding Path=FilteredServiceList, Mode=OneWay}"
Margin="5"/>
Wednesday, March 04, 2009 6:04:45 PM (W. Europe Standard Time, UTC+01:00)
I think I figured it out, but I'm highly confused :)

Basically, after I loaded the FilteredServiceList list(from database, async of course), I had to call raisepropertychanged on like all the lists and it then worked.

Basically I saw in your diver code, your fire raisedpropertychanged events all over the place.

I'm honestly not sure why, since each of these lists are either Observable or INotifyPropertyChanged on the setters ?

I guess it just needs to be told manually that your done populating the list - so fire it so the control can bind to it again ?

:) (if you can't tell, I'm new to xaml/silverlight/wpf - thanks for your patience)
Friday, March 06, 2009 9:40:23 AM (W. Europe Standard Time, UTC+01:00)
i really appreciate for sharing your knowledge about Auto Complete textbox control.
But still i am practicing on it.and learning this.this really gives mentioned flexibility..
Wednesday, March 18, 2009 2:29:58 PM (W. Europe Standard Time, UTC+01:00)


I can see that you are putting a lot of time and effort into your blog and detailed articles! I am deeply in love with every single piece of information you post here. Reading this post reminds me of my old room mate! He always kept talking about this. I will forward this article to him. Pretty sure he will have a good read. Thanks for sharing!
Friday, March 20, 2009 12:08:25 PM (W. Europe Standard Time, UTC+01:00)
Hi Steve,

You have to fire PropertyChanged if you get a NEW object (list). In that case Silverlight has to re-bind and hook the CollectionChanged events.

So, say you return a ObservableCollection from your Service, and a you set it as a property on your VM, in that case you are actually replacing the old ObservableCollection, instead of adding items to it... So in that case you have to fire the event.

Another option would be to NOT re-set the property, and rather call Clear on the collection, and then add in one item at a time. In that case it would be the same object, and silverlight would not have to rebind. And for each item oyu add, the event would fire and the UI would update itself.
Sunday, March 22, 2009 12:48:20 PM (W. Europe Standard Time, UTC+01:00)
Thanks for let me know about auto complete taxtboxesI tried the codes.thanks for all this .
Saturday, May 16, 2009 12:20:12 AM (W. Europe Daylight Time, UTC+02:00)
Hi Jonas

Excellent article... I was searching for a post like this (real use of AutocompleteBox :-)).

About the ObservableCollection and the clear + add elements (maintain the reference to the collection), have you tried it on an AutocompleteBox?

In theory the AutocompleteBox should be smart enough and whenever he receives an notification of new row add / removed it should update his dropdown but tried that and no sucess (I have to manually rebind the collection).

Is that a known issue?

Thanks
Braulio
Monday, May 18, 2009 8:20:46 PM (W. Europe Daylight Time, UTC+02:00)
Hi Braulio,

And thanks for your comment! I'm glad you found the post usefull. I agree that the AutoCompleteBox should be able to bind to an ObservableCollection (as it does in many of the toolkit sampleS), and as you add or remove items it should update it self. I can't remember to have bumbed into any issues with this. If you have troubles getting this to work my recommondation would be to create a simple repro and post a message on the Silverlight Toolkit forum up on Codeplex.

Let me know if you can't figure it out, or when you have posted an example of your problem.

Good luck!

- Jonas
Monday, November 09, 2009 1:42:22 PM (W. Europe Standard Time, UTC+01:00)
Hi

Is it possible to add a button and list of items in the drop down for Autocomplete text box.
sreekanth Boya
Friday, November 27, 2009 9:17:50 PM (W. Europe Standard Time, UTC+01:00)
Hi Jonas, great article!.
I can't find the source code for the Autocomplete, could you tell me where to find it?.

Thanks.
Fer
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, strike) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview
<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910