WPF Editable ComboBox

Here's a basic MVVM compliant way of getting the behaviour you want:

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <ComboBox Margin="30,5,30,5"
                  IsEditable="True"
                  ItemsSource="{Binding Items}"
                  SelectedItem="{Binding SelectedItem}"
                  Text="{Binding NewItem, UpdateSourceTrigger=LostFocus}"/>
        <TextBox Margin="30,5,30,5" />
    </StackPanel>
</Window>

MainWindow.cs

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private string _selectedItem;

    private ObservableCollection<string> _items = new ObservableCollection<string>()
    {
        "One",
        "Two",
        "Three",
        "Four",
        "Five",
    };

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    public IEnumerable Items
    {
        get { return _items; }
    }

    public string SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;
            OnPropertyChanged("SelectedItem");
        }
    }

    public string NewItem
    {
        set
        {
            if (SelectedItem != null)
            {
                return;
            }
            if (!string.IsNullOrEmpty(value))
            {
                _items.Add(value);
                SelectedItem = value;
            }
        }
    }

    protected void OnPropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

I had to place another control in the window as I have set the UpdateSourceTrigger property of the Text binding to LostFocus. If there are no other controls in the window then the Combobox will never lose focus.

I changed the update mode because the default update mode is Propertychanged which will add a new item for each keystroke.

E.G. if you entered the text "Window", the following would be added to your collection:

W
Wi
Win
Wind
Windo
Window

I would handle it in the LostFocus event.

Here you can check if the SelectedItem is null. If so, add the value of Text to the bound list and set SelectedItem to the new item.

In XAML:

  <ComboBox Name="_list" LostFocus="LostFocus" IsEditable="True"/>

In code-behind:

    private ObservableCollection<string> _names;
    public MainWindow()
    {
        InitializeComponent();
        _names = new ObservableCollection<string> {"Eric", "Phillip"};
        _list.SetBinding(ItemsControl.ItemsSourceProperty, new Binding {Source = _names});
    }

    private void LostFocus(object sender, RoutedEventArgs e)
    {
        var comboBox = (ComboBox) sender;
        if(comboBox.SelectedItem != null)
            return;
        var newItem = comboBox.Text;
        _names.Add(newItem);
        comboBox.SelectedItem = newItem;
    }

Hope this helps :)


My suggestion would be using an MVVM-approach and bind your ComboBox.Text to some TextProperty of your ViewModel. (Same can be achieved by just adding a string property to your view) Then you can treat the input in the setter of this property and add that new item to the list, no matter which way it was "committed" in the view. AFAIK there is no out-of-the-box mechanism to add new items to your datasource, you will have to do the item-generation yourself anyway.

Alternatively, you can bind both - SelectedItem and Text of your ComboBox - to avoid lookups in case the user has entered a known item. But that part may be less important to answer your question.