views:

434

answers:

2

I have a Nationality ComboBox like the one below and want to make it so that the user can type letters to narrow in on the choices. I could solve this the way I started below by adding logic in the NationalityComboBox_KeyDown method.

Is this the best way to build AutoSuggest into a ComboBox or is there a built-in way to do the same thing?

XAML:

<ComboBox x:Class="TestComboSuggest343.NationalityComboBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Value}"/>
        </DataTemplate>        
    </ComboBox.ItemTemplate>
</ComboBox>

Code-Behind:

public partial class NationalityComboBox : ComboBox
{
    public NationalityComboBox()
    {
        InitializeComponent();

        Items.Add(new KeyValuePair<string, string>(null, "Please choose..."));
        Items.Add(new KeyValuePair<string, string>(null, "American"));
        Items.Add(new KeyValuePair<string, string>(null, "Australian"));
        Items.Add(new KeyValuePair<string, string>(null, "Belgian"));
        Items.Add(new KeyValuePair<string, string>(null, "French"));
        Items.Add(new KeyValuePair<string, string>(null, "German"));
        Items.Add(new KeyValuePair<string, string>(null, "Georgian"));
        SelectedIndex = 0;

        KeyDown += new KeyEventHandler(NationalityComboBox_KeyDown);

    }

    void NationalityComboBox_KeyDown(object sender, KeyEventArgs e)
    {
        SelectedIndex = 4; // can create logic here to handle key presses, e.g. "G", "E", "O"....
    }
}
A: 

Check out the auto complete text boxes provided in the Silverlight Toolkit. I believe they're available for WPF too.

You can see it in action in this XBAP demo. Look for AutoCompleteBox.

Drew Noakes
+1  A: 

I wrote an attached property to do that :

public class ComboBoxAutoFilter
{
    public static bool GetEnabled(DependencyObject obj)
    {
        return (bool)obj.GetValue(EnabledProperty);
    }

    public static void SetEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(EnabledProperty, value);
    }

    // Using a DependencyProperty as the backing store for Enabled.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty EnabledProperty =
        DependencyProperty.RegisterAttached(
            "Enabled",
            typeof(bool),
            typeof(ComboBoxAutoFilter),
            new UIPropertyMetadata(false, Enabled_Changed)
        );

    private static void Enabled_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        ComboBox combo = sender as ComboBox;
        if (combo != null)
        {
            if (combo.Template != null)
                SetTextChangedHandler(combo);
            else
                combo.Loaded += new RoutedEventHandler(combo_Loaded);
        }
    }

    static void combo_Loaded(object sender, RoutedEventArgs e)
    {
        ComboBox combo = sender as ComboBox;
        combo.Loaded -= combo_Loaded;
        if (combo.Template != null)
            SetTextChangedHandler(combo);
    }

    private static void SetTextChangedHandler(ComboBox combo)
    {
        TextBox textBox = combo.Template.FindName("PART_EditableTextBox", combo) as TextBox;
        if (textBox != null)
        {
            bool enabled = GetEnabled(combo);
            if (enabled)
                textBox.TextChanged += textBox_TextChanged;
            else
                textBox.TextChanged -= textBox_TextChanged;
        }
    }

    private static void textBox_TextChanged(object sender, RoutedEventArgs e)
    {
        TextBox textBox = sender as TextBox;
        ComboBox combo = textBox.TemplatedParent as ComboBox;
        combo.IsDropDownOpen = true;
        string text = textBox.Text.Substring(0, textBox.SelectionStart);
        combo.Items.Filter = value => value.ToString().StartsWith(text);
    }

}

You can use it like that :

    <ComboBox IsEditable="True"
              local:ComboBoxAutoFilter.Enabled="True">
        <sys:String>American</sys:String>
        <sys:String>Australian</sys:String>
        <sys:String>Belgian</sys:String>
        <sys:String>French</sys:String>
        <sys:String>German</sys:String>
        <sys:String>Georgian</sys:String>
        ...
    </ComboBox>
Thomas Levesque
1) There is an out-the-box property "IsSearchFilterEnabled".2) The problem is that when this property is enabled, it auto-completes the word. Is there anyway to avoid this?
Shimmy