Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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();
}
};
};
}
@yasithmilinda

This comment has been minimized.

Copy link

@yasithmilinda yasithmilinda 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

This comment has been minimized.

Copy link

@devMagics devMagics commented Apr 14, 2017

what MaxValue means ?

@Lerosbeef

This comment has been minimized.

Copy link

@Lerosbeef Lerosbeef commented May 23, 2017

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

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

@vogelor

This comment has been minimized.

Copy link

@vogelor vogelor commented Feb 6, 2019

what MaxValue means ?

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

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