具有来自 itemsource 或用户输入的选定值(路径)的可编辑组合框

Posted

技术标签:

【中文标题】具有来自 itemsource 或用户输入的选定值(路径)的可编辑组合框【英文标题】:Editable ComboBox with selectedvalue(path) from itemsource OR user input 【发布时间】:2021-02-05 12:41:00 【问题描述】:

嘿,我正在尝试创建一个组合框,允许用户从列表中选择一个项目(在列表中显示为 fx。“2324 - James - 21”),将该项目的属性放入文本框中(fx ."James"),还允许用户输入该属性。 (fx。“杰克”)

What I've got so far is a combobox that allows for user input, but when an item is selected, instead of the property (As specified in SelectedValuePath), the items ToString is put in组合框文本字段,而不仅仅是名称。 任何想法如何解决它?这是我现在的设置:

人物类:

public class Person

    public int Id  get; set; 
    public string Name  get; set; 
    public int Age  get; set; 

    public override string ToString()
    
        return $"Id - Name - Age";
    

XAML:

<ComboBox Text="Binding PersonName, UpdateSourceTrigger=PropertyChanged" 
ItemsSource="Binding People, UpdateSourceTrigger=PropertyChanged, Mode=OneWay"
SelectedValue="Binding PersonName, UpdateSourceTrigger=PropertyChanged" 
IsEditable="True" SelectedValuePath="Name" /> 

编辑:

People 是 ObservableCollection,PersonName 是绑定到字段 personName 和 OnPropertyChanged() 的字符串;在其 set 方法中调用。 ViewModel 从实现 INotifyPropertychanged 的​​ ObservableObject 类继承。

编辑 2:

好的,所以我一直在尝试这个:

<ComboBox Text="Binding PersonName, UpdateSourceTrigger=PropertyChanged" 
ItemsSource="Binding People, UpdateSourceTrigger=PropertyChanged, Mode=OneWay"
SelectedItem="Binding Person, UpdateSourceTrigger=PropertyChanged" 
IsEditable="True" /> 

视图模型中的 Aaand:

public Person SelectedPerson

    get => selectedPerson;
    set
    
        selectedPerson = value;
        OnPropertyChanged();
        if (SelectedPerson != null) PersonName = SelectedPerson.Name;
    

但是,当我从列表中选择一个人时,组合框文本字段设置为 Persons ToString 值,而不是 SelectedPerson.Name... 或者更确切地说;它可能首先设置为 SelectedPerson.Name,然后由 ComboBox 自动设置为 SelectedPerson.ToString() :/

编辑 3:

好吧,我一直试图中断文本更改,当它以一种非常糟糕的方式来自 SelectionChanged 时,但我不知道如何“取消”文本更改。到目前为止,这是我的代码,但据我所知,TextChanged 似乎不允许恢复文本,并且 PreviewTextInput 仅在表单用户输入更改时触发:/。

Useless code removed. Almost identical to edit 4, but without the "oldtext" field.

编辑 4:

我以一种可怕的方式解决了它。它有效,但我真的希望有更好的方法。也许你们中的一个人有更好的解决方案? :) 无论如何,这是我的解决方案:

在组合框强制更改文本后恢复文本的依赖属性:

public class ComboBoxBehaviour

    private static bool overrideTextChange;
    private static string oldText;

    public static bool GetDisconnectTextFromSelectedItem(ComboBox comboBox)
    
        return (bool)comboBox.GetValue(DisconnectTextFromSelectedItemProperty);
    
    public static void SetDisconnectTextFromSelectedItem(ComboBox comboBox, bool value)
    
        comboBox.SetValue(DisconnectTextFromSelectedItemProperty, value);
    

    public static readonly DependencyProperty DisconnectTextFromSelectedItemProperty =
        DependencyProperty.RegisterAttached(
            "DisconnectTextFromSelectedItem",
            typeof(bool),
            typeof(ComboBoxBehaviour),
            new UIPropertyMetadata(false, OnDisconnectTextFromSelectedItemChanged));

    private static void OnDisconnectTextFromSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    
        var comboBox = d as ComboBox;
        if (comboBox == null) return;

        if (e.NewValue is bool == false) return;

        if ((bool)e.NewValue)
        
            comboBox.SelectionChanged += HandleSelection;
            comboBox.Loaded += ComboBoxOnLoaded;
        
        else
        
            comboBox.SelectionChanged -= HandleSelection;
            comboBox.Loaded -= ComboBoxOnLoaded;
        
    
    private static void ComboBoxOnLoaded(object sender, RoutedEventArgs e)
    
        ComboBox comboBox = (ComboBox)e.Source;
        TextBox txtBox = (TextBox)comboBox.Template.FindName("PART_EditableTextBox", comboBox);
        txtBox.TextChanged += TxtBoxOnTextChanged;
    
    private static void TxtBoxOnTextChanged(object sender, TextChangedEventArgs e)
    
        if (overrideTextChange)
        
            ((TextBox) e.Source).Text = oldText;
            overrideTextChange = false;
            e.Handled = true;
        
    
    private static void HandleSelection(object sender, RoutedEventArgs e)
    
        ComboBox comboBox = (ComboBox)e.Source;
        TextBox txtBox = (TextBox)comboBox.Template.FindName("PART_EditableTextBox", comboBox);
        oldText = txtBox.Text;
        overrideTextChange = true;
        e.Handled = true;
    

Xaml 组合框:

<ComboBox Text="Binding PersonName, UpdateSourceTrigger=PropertyChanged" 
ItemsSource="Binding People, UpdateSourceTrigger=PropertyChanged, Mode=OneWay"
SelectedItem="Binding Person, UpdateSourceTrigger=PropertyChanged" 
IsEditable="True" helpers:ComboBoxBehaviour.DisconnectTextFromSelectedItem="True" /> 

编辑 5: 关闭,但没有雪茄。原来是打电话

((TextBox) e.Source).Text = oldText;

不会更新我的组合框文本绑定,因此它显示了正确的文本,但视图模型中的字符串是错误的 - 它是 ToString 文本,而不是短文本。那么,当我无权访问文本更改上下文中的组合框时,如何强制刷新组合框绑定?更多“黑客”?嗯……

编辑 6: 好的,我通过将 TxtBoxOnTextChanged 更改为此来工作;

private static void TxtBoxOnTextChanged(object sender, TextChangedEventArgs e)

    if (overrideTextChange) //The combo box changed the text of the textbox.
    
        TextBox textBox = (TextBox) e.Source; //The textbox
        ComboBox comboBox = (ComboBox)textBox.TemplatedParent; //The combobox.
        comboBox.Text = oldText; //Set the text of the combobox to update the property on the viewmodel.
        textBox.Text = oldText; //Set the text of the textbox manually, because setting the combobox text doesn't change it for some reason.
        overrideTextChange = false;
        e.Handled = true; //Done!
    

仍然希望有人有更好的解决方案,但它确实有效!

【问题讨论】:

如果你删除Text="Binding PersonName, UpdateSourceTrigger=PropertyChanged" 会发生什么? @mm8 如果我删除文本绑定,它仍会在组合框中显示 ToString 值,但 PersonName 已正确设置为 Name 属性,但如果用户手动输入名称,则不会设置 PersonName。 将 DisplayMemberPath 设置为 Name? @mm8 不能这样做,那么列表中的项目只显示名称 - 我需要列表具有完整的 ToString 值。也不影响用户输入 在弹出的实际列表中我需要显示 ToString,但在手动输入字段中我只需要显示 Name 属性。 【参考方案1】:

如果要显示Name 属性的值而不是ToString(),则应将DisplayMemberPath 属性设置为“名称”。

我需要在列表中显示 ToString,但在输入字段中显示名称。

那么你应该将PersonName设置为你想在输入字段中显示的string,并且不要将SelectedValue绑定到PersonName

您实际上只能选择源集合中的值。

【讨论】:

我需要在列表中显示 ToString,但在输入字段中显示名称。 输入字段显示当前选择的值,您只能选择ItemsSource集合中的值。 好吧,这很有意义。我首先尝试了类似的东西但没有成功。再次尝试以防万一并更新了我的问题。还是不太对:/

以上是关于具有来自 itemsource 或用户输入的选定值(路径)的可编辑组合框的主要内容,如果未能解决你的问题,请参考以下文章

访问 ComboBox 绑定和选定值

来自具有相同类名的段落的输入或字符串的值总和始终显示“0”

WPF ListBox 值来自另一个选定的 ListBox 项,然后上下移动

如何根据先前表单字段的选定选项值隐藏表单字段

将最后一个表格行的选定值复制到新行

具有联接表和来自 GET 参数的多个值的高级查询