WPF 可编辑组合框

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3373239/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 21:58:51  来源:igfitidea点击:

WPF Editable ComboBox

wpf

提问by rs199483

I have a ComboBox and ComboBox.IsEditable property is set to True to have a ComboBox act as both a TextBox and a drop-down list simultaneously. But when the ComboBox is data-bound, entering custom text will not cause a new item to be added to the data-bound collection.

我有一个 ComboBox 并且 ComboBox.IsEditable 属性设置为 True 以使 ComboBox 同时充当 TextBox 和下拉列表。但是当 ComboBox 是数据绑定的时,输入自定义文本不会导致将新项目添加到数据绑定集合中。

For example, if I enter 'Joe' in a ComboBox that is bound to a list of people, which doesn't contain the value 'Joe', then the value 'Joe' is not going to be added to the drop-down list automatically.

例如,如果我在绑定到不包含值“Joe”的人员列表的 ComboBox 中输入“Joe”,则不会将值“Joe”添加到下拉列表中自动地。

What is the best way to handle this?

处理这个问题的最佳方法是什么?

回答by Benjamin Gale

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

MVVM是获得所需行为的基本合规方式:

MainWindow.xaml

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

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 UpdateSourceTriggerproperty of the Textbinding to LostFocus. If there are no other controls in the window then the Comboboxwill never lose focus.

我必须在窗口中放置另一个控件,因为我已将绑定的UpdateSourceTrigger属性设置TextLostFocus. 如果窗口中没有其他控件,则Combobox永远不会失去焦点。

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

我更改了更新模式,因为默认更新模式是Propertychanged为每次击键添加一个新项目。

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

例如,如果您输入文本“Window”,以下内容将添加到您的收藏中:

W
Wi
Win
Wind
Windo
Window

回答by Goblin

I would handle it in the LostFocus event.

我会在 LostFocus 事件中处理它。

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.

在这里您可以检查 SelectedItem 是否为空。如果是,则将 Text 的值添加到绑定列表并将 SelectedItem 设置为新项。

In XAML:

在 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 :)

希望这可以帮助 :)

回答by Simon D.

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.

我的建议是使用 MVVM 方法并将 ComboBox.Text 绑定到 ViewModel 的某些 TextProperty。(同样可以通过向您的视图添加一个字符串属性来实现)然后您可以处理此属性的 setter 中的输入并将该新项目添加到列表中,无论它在视图中以哪种方式“提交”。AFAIK 没有现成的机制可以将新项目添加到您的数据源,无论如何您都必须自己进行项目生成。

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.

或者,您可以同时绑定 - SelectedItem 和 ComboBox 的文本 - 以避免在用户输入已知项目时进行查找。但这部分对于回答您的问题可能不太重要。