Haven’t you always wanted to use a combo box like the one in Start menu’s Run dialog?
A client asked me for the exact same thing, and now you can download it from here too. The Automatically Filtered ComboBox inherits from the original ComboBox and adds the auto-filtering, along with an ability to filter while ignoring case. The IsTextSearchEnabled property already allows you to do all this (and the use of which is therefore supported), but it doesn’t allow for case sensitivity and filtration of the results.
Interesting bits about the code:
/// <summary>
/// Gets the text box in charge of the editable portion of the combo box.
/// </summary>
protected TextBox EditableTextBox
{
get
{
return ((TextBox)base.GetTemplateChild("PART_EditableTextBox"));
}
}
The above section of code lets you access the text box that sits at the top of the combo box. We use this text box to get the selection (just like what we could get from a ComboBox in Windows Forms using the SelectedText property).
ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
view.Filter += this.FilterPredicate;
ICollectionView view = CollectionViewSource.GetDefaultView(this.ItemsSource);
view.Refresh();
The above two piece of code use the CollectionViewSource class to create a filter on the default view of the ItemsSource. This mechanism is used internally by the original ComboBox to filter and/or sort the source of the items. I’m a bit baffled by why the WPF team would decide on only using a single, global view for the items’ source, rather than a model like the one presented in ADO.NET using the DataView on DataTables. Thanks to Tomer for the heads up on that one.
private bool FilterPredicate(object value)
{
// We don't like nulls.
if (value == null)
return false;
// If there is no text, there's no reason to filter.
if (this.Text.Length == 0)
return true;
string prefix = this.Text;
// If the end of the text is selected, do not mind it.
if (this.length > 0 && this.start + this.length == this.Text.Length)
{
prefix = prefix.Substring(0, this.start);
}
return value.ToString()
.StartsWith(prefix, !this.IsCaseSensitive, CultureInfo.CurrentCulture);
}
The above is the predicate for filtering. As you can see, only items that start with the text already in the box are kept in the list (Yes, value.ToString() is not a correct implementation; I will change it in the future). Notice that if the selection is on the end of the text, we do not use that part for the search, since the very next character pressed will replace the selected text and we would like to show the possible results for such a keystroke.
As I am still in the process of getting used to WPF, there is still much to learn. I would gladly accept any comment you may have about the means to the end and also on my style and conventions. You always have something new to learn :)
this is cool, I like the code
Hi Sounds cool, but Im new to WPF and wondering how to implement this class with a combobox declared in XAML. thx in Advance
I doubt it very much that this can be done with XAML only and no code.
Do you have a WPF sample application that uses this customized control?
Sorry, no, but you can simply use it like any other combo box. Just replace the usual name with the control’s name and voila. :)
You can do this in XAML. Look at IsTextSearchEnabled
& TextSearch.TextPath.
Reference
http://msdn2.microsoft.com/en-us/library/system.windows.controls.textsearch.aspx
http://msdn2.microsoft.com/en-us/library/system.windows.controls.itemscontrol.istextsearchenabled.aspx
FTA: “The IsTextSearchEnabled property already allows you to do all this (and the use of which is therefore supported), but it doesn’t allow for case sensitivity and filtration of the results.”
Great stuff :)
This code appears to throw in the getter for EditableTextBox if you are in the VS designer.
One possible workaround is to wrap the addition of the event handler and check to see if (this.EditableTextBox != null) first.
Also, should we be using
return Template.FindName(“PART_EditableTextBox”, this) as TextBox;
instead of GetTemplateChild?
Hey casper,
Thanks for the comment. It’s been a while since I touched the code, so maybe there are a few things I have missed. I hope whomever decides to use the code reads your comments and tries your suggestions, at the moment, I’m too far from WPF development to answer :)
Not working though. Neither with GetTemplateChild nor with Template.FindName…
Hi,
I used the autofiltercombobox given here but i am not able to display the filtered item list on a popup like you have shown in the snapshot above. Can you please tell me how i can display a popup below the combobox which contains a filtered list of items based on the text entered.
Casper & Archimed7592, make sure you have the IsEditable property set to true in your XAML otherwise the retrieval of the template will fail since there is no TextBox to get.
Regarding the ToString() thing, I used a bit of reflection to get the value of the property identified by DisplayMemberPath:
string textValue = string.Empty;
if (!string.IsNullOrEmpty(this.DisplayMemberPath))
{
Type t = value.GetType();
var displayMemberPathProperty = t.GetProperty(this.DisplayMemberPath);
if (displayMemberPathProperty != null)
{
textValue = displayMemberPathProperty.GetValue(value, null).ToString();
}
}
if (textValue.Length == 0)
textValue = value.ToString();
return textValue.StartsWith(prefix, !this.IsCaseSensitive, CultureInfo.CurrentCulture);
May I suggest that you include the solution instead of the mere file? It would save a lot of people the time of trying to get the sample to work and would be a proof of consept.
I could not get it to work myself, as I’m a bit new in the WPF terrain, have to research some more I guess.
Daniel,
Since it’s been well over a year since I stopped doing WPF work and changes jobs, I unfortunately can’t find the solution itself to attach. Sorry.
Sabe alguien hacerlo para un listview.
“I’m a bit baffled by why the WPF team would decide on only using a single, global view for the items’ source, rather than a model like the one presented in ADO.NET using the DataView on DataTables. Thanks to Tomer for the heads up on that one.”
You don’t have to use the default view. You can create your own collection view, usually in xaml, and then bind to it. However, if you just bind directly to the collection, then the combo box will automitcally use the default view.
JTango alluded to this already but I have found that after struggling with exceptions with the code that there are pre-requisites in the Xaml use of this control that were invisible as the author only published the *.cs file.
I have found that in order for it to work as described by the auther both IsEditable (required to get the correct template for a ComboBox as the default template does not contain a Part_EditableTextbox), and IsTextSearchEnabled must be set to true. Also for the filtering to be considered the control must be using ItemsSource.
See workable Xaml below.
Simon
Dude, I have been messing around with this stupid file for the last hour. Either put up a damn solution (SLN) or take this crap down so as not to waste people’s time.
I have tried this with VS2008 and cannot get it to work as shown in your screenshot above. I have set IsEditable to true and IsTextSearchEnabled to false and also tried some other variants. I have also tried to incorporate the fixing code by another commenter above. It simply does not work. I think, there must have been more code than what you are publishing here. Therefore, this page is rather confusing and should be removed.
I have tried this with VS2008 and cannot get it to work as shown in your screenshot above. I have set IsEditable to true and IsTextSearchEnabled to false and also tried some other variants. I have also tried to incorporate the fixing code by another commenter above. It simply does not work. I think, there must have been more code than what you are publishing here. Therefore, this page is rather confusing and should be removed.
When I type into my combobox the CPU just goes nuts. Anyone experience any strange loops when implementing this code? I havent altered it at all. My itemsSource has about 450 elements.
See this:
http://dotbay.blogspot.com/2009/04/building-filtered-combobox-for-wpf.html
If you want to use this in a WPF application AVOID!!!!!! Shame it mention WPF in the title.
Hi,
What should i write in xaml to implement this functionality, means what properties i need to set in xaml ?
Crashed right now on base.GetTemplateChild(“PART_EditableTextBox”);
Hi Clifford,
As you can see from the date on this blog post, this was done several years ago with a very old version of WPF. I’m pretty sure most of the hacks I posted to this blog would not work by now, since they work based on undocumented behavior.
However, you can take this as inspiration and try to change whatever it is that didn’t work for it to work.
Omer