Skip to content

Instantly share code, notes, and snippets.

@mariodivece
Created January 3, 2015 07:15
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mariodivece/0bbade976aea8d416d52 to your computer and use it in GitHub Desktop.
Save mariodivece/0bbade976aea8d416d52 to your computer and use it in GitHub Desktop.
Makes a WPF ComboBox Searchable via its items
public static void MakeComboBoxSearchable(this ComboBox targetComboBox)
{
targetComboBox.Loaded += (ls, le) =>
{
targetComboBox.Items.IsLiveFiltering = true;
var targetTextBox = targetComboBox.Template.FindName("PART_EditableTextBox", targetComboBox) as TextBox;
if (targetTextBox == null) return;
targetComboBox.IsEditable = true;
targetComboBox.IsTextSearchEnabled = false;
targetTextBox.Tag = "Selection";
targetTextBox.PreviewKeyDown += (se, ev) =>
{
if (ev.Key == Key.Enter || ev.Key == Key.Return || ev.Key == Key.Tab)
return;
targetTextBox.Tag = "Typed";
if (targetComboBox.SelectedItem != null)
{
targetComboBox.SelectedItem = null;
targetComboBox.Text = string.Empty;
}
};
targetTextBox.TextChanged += (se, ev) =>
{
var searchTerm = string.Empty;
if (string.IsNullOrWhiteSpace(targetTextBox.Text) == false && (string)targetTextBox.Tag == "Typed")
{
targetComboBox.SelectedItem = null;
targetComboBox.IsDropDownOpen = true;
searchTerm = targetTextBox.Text.ToLowerInvariant();
targetTextBox.Select(targetTextBox.Text.Length, 0);
targetComboBox.Items.Filter = (filterItem) =>
{
return filterItem.ToString().ToLowerInvariant().Contains(searchTerm);
};
}
else
{
targetComboBox.Items.Filter = (filterItem) => { return true; };
}
targetComboBox.Items.Refresh();
};
targetComboBox.SelectionChanged += (se, ev) =>
{
if (targetComboBox.SelectedItem != null)
{
targetTextBox.Tag = "Selection";
targetComboBox.Items.Filter = (filterItem) => { return true; };
targetComboBox.Items.Refresh();
}
};
};
}
@yasithdev
Copy link

yasithdev commented Sep 6, 2016

This method was an immense use for me for my last project. However, it had its own set of unique problems similar to most solutions found online; being, the comboBox not allowing to change the selected value by using up/down arrow keys once a you select an item, delete part of text or change it completely, and search for a new set. It apparently loses focus, and the only workaround I figured was to lose Keyboard Focus and Refocus on the control. Hence I made a modified version of the code and I am posting it here for the benefit of anyone who stumbles across this.

Key points to note:

1. IsLiveFiltering = true is not needed for most purposes and it consumes considerable memory
2. PreviewKeyDown event handler is not needed if this method of implementation is followed

and few more improvements were made. Good luck :)

public static class Extensions
    {
        public static void MakeComboBoxSearchable(this ComboBox targetComboBox)
        {
                targetComboBox.Loaded += TargetComboBox_Loaded;
        }

        private static void TargetComboBox_Loaded(object sender, RoutedEventArgs e)
        {
            var targetComboBox = sender as ComboBox;
            var targetTextBox = targetComboBox?.Template.FindName("PART_EditableTextBox", targetComboBox) as TextBox;

            if (targetTextBox == null) return;

            targetComboBox.Tag = "TextInput";
            targetComboBox.StaysOpenOnEdit = true;
            targetComboBox.IsEditable = true;
            targetComboBox.IsTextSearchEnabled = false;

            targetTextBox.TextChanged += (o, args) =>
            {
                var textBox = (TextBox) o;

                var searchText = textBox.Text;

                if (targetComboBox.Tag.ToString() == "Selection")
                {
                    targetComboBox.Tag = "TextInput";
                    targetComboBox.IsDropDownOpen = true;
                }
                else
                {
                    if (targetComboBox.SelectionBoxItem != null)
                    {
                        targetComboBox.SelectedItem = null;
                        targetTextBox.Text = searchText;
                        textBox.CaretIndex = MaxValue;
                    }

                    if (string.IsNullOrEmpty(searchText))
                    {
                        targetComboBox.Items.Filter = item => true;
                        targetComboBox.SelectedItem = default(object);
                    }
                    else
                        targetComboBox.Items.Filter = item =>
                                item.ToString().StartsWith(searchText, true, CultureInfo.InvariantCulture);

                    Keyboard.ClearFocus();
                    Keyboard.Focus(targetTextBox);
                    targetTextBox.CaretIndex = MaxValue;
                    targetComboBox.IsDropDownOpen = true;
                }
            };


            targetComboBox.SelectionChanged += (o, args) =>
            {
                var comboBox = o as ComboBox;
                if (comboBox?.SelectedItem == null) return;
                comboBox.Tag = "Selection";
            };
        }
    }

@devMagics
Copy link

devMagics commented Apr 14, 2017

what MaxValue means ?

@Lerosbeef
Copy link

This is great! I replaced:
targetTextBox.CaretIndex = MaxValue; targetComboBox.IsDropDownOpen = true;

With:
targetComboBox.IsDropDownOpen = true; targetTextBox.SelectionStart = targetTextBox.Text.Length;

@vogelor
Copy link

vogelor commented Feb 6, 2019

what MaxValue means ?

i know this question is old. But: MaxValue = int.MaxValue

@quoctrunggol
Copy link

I tried the above Extension, it fixed the SelectItem when DropDownOpen. But when searchingBox it doesn't get the binding value of Itemsources anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment