【发布时间】: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 属性。