Enhancing AutoCompleteBox part 1: distinguishing similar items
Among other novelties Silverlight 3 also included new and very useful AutoCompleteBox allowing to make smart suggestions to a user during text input. Unfortunately, as it always happens with new and pretty complex controls like that, there are some scenarios when you can't avoid changing or enhancing its default behavior to get the functionality you want.
The first thing I'd like to discuss is how to make AutoCompleteBox work like combo: not only selecting the text you want, but also selecting the object you want. As it turns out, AutoCompleteBox is not a perfect candidate for implementing this functionality: you'll need to extend the code a little to make it work smoothly.
Problems start when you need to distinguish objects which are represented by the same text in AutoCompleteBox's text box. For example, you are implementing an AutoCompleteBox for editing persons LastName. In a dropdown list, you display person's FullName (FirstName+LastName), but in textbox - only LastName. Than, you bind your Person property to AutoCompleteBox.SelectedItem and expect that you'll get as SelectedItem the object you selected in list. But no: selecting second person with the same name
makes AutoCompleteBox thinks that the first item is selected!
This is actually a well-known problem discussed on Silverlight forums. AutoCompleteBox creators recommend to avoid this scenario completely, but actually, not all is that bad, this problem is fixable in a rather simple way. Unfortunately, custom ItemFilters and overriding FormatValue won't help here: it all goes to the same string displayed in AutoCompleteBox text box. When you do a selection in popup, AutoCompleteBox remembers only this string. To get a selected item, it searches again in the whole list and, surely, is having troubles with duplicates, as the information about the actual selection is lost. But can fix it - just make it remember. In your custom class inherited from AutoCompleteBox, define a new dependency property (name it, for example, SelectionBoxItem like it was named in ComboBox), than override OnDropDownClosing:
protected override void OnDropDownClosing(RoutedPropertyChangingEventArgs<bool> e) { base.OnDropDownClosing(e); SelectionBoxItem = SelectionAdapter.SelectedItem; }
You'll need to bind to SelectionBoxItem instead of SelectedItem to get the proper item from selection. Nothing spectacular, but it works, as you may see in the demo attached.
| Attachment | Size |
|---|---|
| autocompleteboxduplicates.zip | 152.08 KB |

Comments
This fix worked like a charm!!
Thanks for posting this fix. It was really annoying and had eaten up a day's effort to fix it.
Making this work with a DataTemplate
Hi Alex,
This is a great fix for the problem, but how do we get this to work with a DataTemplate? I really appreciate your help.
Thanks very much in advance.
Re: making this work with DataTemplate
Thanks, glad this workaround was helpful. About DataTemplate: I'm not sure what's causing your problem, just write any valid ItemTemplate to AutoCompleteBoxEx and it should work. We're actually using this workaround with DataTemplate without problems. You may check it by specifying an ItemTemplate to AutoCompleteBoxEx in the sample, for example:
dint work for me ?
Hello
I am trying to fix the problem like this :
I have created the helper class for autocomplete and derived it from 'Autocomplete'. Everything is same and I am usinh DataTemplate in autocomplete box. But it still goes in selectionchanged method twice and get the wrong id in second time . Its so annoying , please help me ...
Thanks
code dint show up
Re: dint work for me ?
It works perfectly in the attached project. Please try to localize this problem and reproduce it by modifying the attached sample project. Most likely you are filling the autocomplete box twice, and it causes problems with synchronization.
ToString
A simpler solution would be to override the ToString method of whatever object you are listing in the popup. This worked great for me.
Re: ToString
No, just overriding ToString() will not help here. As you see in the attached project, Person.ToString() method is already overriden (just to display readable text in combo), however it doesn't solve the duplication problem.
And even if it'll help, it's not a good solution, as it requires overriding ToString() in every class displayed in AutoCompleteBox, and different ToString() functionality may be needed somewhere else.