我有一个 ComboBox
绑定(bind)到我的 ViewModel 上的一个属性(从“VM”上听到)。当用户在 ComboBox
上进行选择时它会正确更新我的 VM 中的绑定(bind)属性。在我的 UI 代码中,我订阅了 PropertyChanged
我的虚拟机上的事件。
正如它应该表现的那样,当用户在 ComboBox
中进行选择时, 我的 PropertyChanged
事件在我的 UI 后端代码中正确执行。当 UI 代码捕捉到此属性的更改时,在某些选择条件下,我需要停止进程并请求用户提供更多信息。从 UI 中,我向他们发送了一个对话框。如果他们取消对话框,我会重置与 ComboBox
关联的 VM 中的值。控制 SelectedValue
.
这是我观察到的。当用户取消操作时,我的 VM 属性被设置为新值。但是,ComboBox
仍然显示现在已更改的原始条目的文本值。如何强制 ComboBox
从我的PropertyChanged
中更新自己事件?在这种情况下,我认为这只是一个文本问题或数字索引更改,它引用了绑定(bind)集合中的文本数据。 VM 中的数据正确,但显示值为 ComboBox
是错的。
示例
组合框详情
<ComboBox
ItemsSource="{Binding ListOfComboBoxDisplayObjects}"
SelectedValue="{Binding MySelectionIsAnEnumeration}"
DisplayMemberPath="Text"
SelectedValuePath="EnumerationValue"
Height="27" />
对虚拟机上的冗长属性感到抱歉,但这是为了解释正在发生的事情。我的
ListOfComboBoxDisplayObjects
collection 表示一组枚举器值,它们存储在 SelectedValuePath
内的路径中。 .每个值的描述性文本来自 ListOfComboBoxDisplayObjects
这是一个为 UI 严格创建的特殊列表。这基本上将枚举值与有意义的描述配对。ListOfComboBoxDisplayObjects 定义(来自 VM)
编辑 #1 - 将此定义添加到我的示例中
private ObservableCollection<BindableEnumerationItem<Values>> _listOfComboBoxDisplayObjects;
public ObservableCollection<BindableEnumerationItem<Values>> ListOfComboBoxDisplayObjects
{
get { return _listOfComboBoxDisplayObjects; }
private set
{
if (value != _listOfComboBoxDisplayObjects)
{
_listOfComboBoxDisplayObjects= value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ListOfComboBoxDisplayObjects)));
}
}
}
MySelectionIsAnEnumeration 定义(来自 VM 内)
*编辑#1:添加此代码定义。
private Values_mySelectionIsAnEnumeration ;
public Values MySelectionIsAnEnumeration
{
get { return _mySelectionIsAnEnumeration; }
set
{
//Double-checked this-- value is different on the second-call to change this value, once the UI cancels the operation.
if (value != _mySelectionIsAnEnumeration)
{
_mySelectionIsAnEnumeration= value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MySelectionIsAnEnumeration )));
}
}
}
与 ListOfComboBoxDisplayObjects 关联的相关值
这些值在 VM 的 ctor 中生成。它们在整个应用程序中都是固定的。
项目 #1
项目#2:
项目#3:
PropertyChanged 事件 - 来自 UI 后端
private void VM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "MySelectionIsAnEnumeration":
if (VM.MySelectionIsAnEnumeration == Values.Baz)
{
//Prompt the user and get DialogResult.
bool answerGiven = AskAQuestionAndGetAResult();
if(!answerGiven)
VM.MySelectionIsAnEnumeration = Values.Foo;
}
break;
}
}
执行上述代码后,我观察到
VM.MySelectionIsAnEnumeration
value 确实正在更改为 Value.Foo
的正确值当用户在 AskAQuestionAndGetAResult()
内取消操作时.然而,在它完成后 ComboBox
还是写着“This is Baz. I need to ask a question才可以使用。”,这显然是与Value.Baz
关联的显示值.如何更新基础 VM 属性和
CombobBox
上的显示文本正确显示现在存储在 VM.MySelectionIsAnEnumeration
中的值?编辑#2
下面是我的
BindableEnumerationItem
的代码我在我的 Observable Collections 中用于组合框和列表框。这在我的整个应用程序中都在更简单的情况下使用,并且没有引起任何问题。请注意,这是我实际的、未更改的代码。我没有重命名任何东西。我的组合框可以绑定(bind)到每个 Item
类型安全属性的属性和 DisplayText
是描述 rune 本。public class BindableEnumerationItem<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private T _item;
public BindableEnumerationItem(T item, string displayText)
{
_item = item;
_displayText = displayText;
}
private string _displayText;
public string DisplayText
{
get { return _displayText; }
set
{
if (value != _displayText)
{
_displayText = value;
PropertyChanged(this, new PropertyChangedEventArgs("DisplayText"));
}
}
}
public T Item
{
get { return _item; }
set
{
_item = value;
PropertyChanged(this, new PropertyChangedEventArgs("Item"));
}
}
}
最佳答案
创建一个扩展,将 xaml 中的 View 模型中的命令连接到选择器,在本例中为组合框。
public partial class Extensions
{
public static readonly DependencyProperty SelectionChangedCommandProperty = DependencyProperty.RegisterAttached("SelectionChangedCommand", typeof(ICommand), typeof(Extensions), new UIPropertyMetadata((s, e) =>
{
var element = s as Selector;
if (element != null)
{
element.SelectionChanged -= OnSelectionChanged;
if (e.NewValue != null)
{
element.SelectionChanged += OnSelectionChanged;
}
}
}));
public static ICommand GetSelectionChangedCommand(UIElement element)
{
return (ICommand)element.GetValue(SelectionChangedCommandProperty);
}
public static void SetSelectionChangedCommand(UIElement element, ICommand value)
{
element.SetValue(SelectionChangedCommandProperty, value);
}
private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var element = sender as Selector;
var command = element.GetValue(SelectionChangedCommandProperty) as ICommand;
if (command != null && command.CanExecute(element.SelectedItem))
{
command.Execute(element.SelectedItem);
e.Handled = true;
}
}
}
在处理值更改事件的 View 模型中创建命令。
public ICommand EnumerationValueChangedCommand
{
get
{
return new Command(
() =>
{
if (VM.MySelectionIsAnEnumeration == Values.Baz)
{
//Prompt the user and get DialogResult.
bool answerGiven = AskAQuestionAndGetAResult();
if (!answerGiven)
VM.MySelectionIsAnEnumeration = Values.Foo;
}
});
}
}
然后使用该扩展名进行绑定(bind)。 ext 是您的扩展的命名空间。
<ComboBox
ItemsSource="{Binding ListOfComboBoxDisplayObjects}"
SelectedValue="{Binding MySelectionIsAnEnumeration}"
DisplayMemberPath="Text"
SelectedValuePath="EnumerationValue"
ext:Extensions.SelectionChangedCommand="{Binding EnumerationValueChangedCommand}"
Height="27" />
关于c# - 如何从 PropertyChanged 事件中正确重置与 ComboBox 关联的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41958534/