具有来自 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
编辑 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 或用户输入的选定值(路径)的可编辑组合框的主要内容,如果未能解决你的问题,请参考以下文章