【发布时间】:2017-01-31 13:12:27
【问题描述】:
我有一个ComboBox,它绑定到我的 ViewModel 上的一个属性(从“VM”上听到)。当用户在ComboBox 上进行选择时,它会正确更新我的 VM 中的绑定属性。在我的 UI 代码中,我在我的 VM 上订阅了 PropertyChanged 事件。
正如它应该表现的那样,当用户在ComboBox 中进行选择时,我的PropertyChanged 事件在我的UI 后端代码中正确执行。当 UI 代码捕捉到此属性的更改时,在某些选择条件下,我需要停止进程并请求用户提供更多信息。从 UI 中,我向他们发送了一个对话框。如果他们取消对话框,我会重置与ComboBox 控件SelectedValue 关联的VM 中的值。
这是我观察到的。当用户取消操作时,我的 VM 属性被设置为新值。但是,ComboBox 仍然显示现在已更改的原始条目的文本值。如何强制 ComboBox 从我的 PropertyChanged 事件中更新自身?在这种情况下,我认为这只是一个文本问题或数字索引更改,它引用了绑定集合中的文本数据。 VM 中的数据正确,但ComboBox 的显示值错误。
示例
组合框详细信息
<ComboBox
ItemsSource="{Binding ListOfComboBoxDisplayObjects}"
SelectedValue="{Binding MySelectionIsAnEnumeration}"
DisplayMemberPath="Text"
SelectedValuePath="EnumerationValue"
Height="27" />
对于虚拟机上的冗长属性,我们深表歉意,但这是为了解释正在发生的事情。我的ListOfComboBoxDisplayObjects 集合表示一组枚举值,这些值存储在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
- 文本:“这是一个 Foo!”
- 值:Values.Foo
项目#2:
- 文本:“嗨,我是 Bar。”
- 值:Values.Bar
项目 #3:
- 文本:“我是 Baz。我需要先问一个问题才能使用。”
- 值:Values.Baz
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;
}
}
执行上述代码后,我观察到当用户取消AskAQuestionAndGetAResult() 中的操作时,VM.MySelectionIsAnEnumeration 的值确实变为Value.Foo 的正确值。但是,完成后ComboBox仍然显示“这是Baz。我需要问一个问题才能使用。”,这显然是与Value.Baz关联的显示值。
如何更新基础 VM 属性和 CombobBox 上的显示文本以正确显示现在存储在 VM.MySelectionIsAnEnumeration 中的值?
编辑#2
下面是我的 BindableEnumerationItem 的代码 e,我在我的 Observable Collections 中用于组合框和列表框。这在我的整个应用程序中都在更简单的情况下使用,并且没有引起任何问题。请注意,这是我实际的、未更改的代码。我没有重命名任何东西。我的组合框可以绑定到每个 Item 属性以获得类型安全的属性,DisplayText 是描述符文本。
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"));
}
}
}
【问题讨论】:
-
如果视图没有更新绑定,那么某处缺少通知或绑定错误。你能显示
ListOfComboBoxDisplayObjects,它的类型和MySelectionIsAnEnumeration吗? -
@Sinatr,
ListOfComboBoxDisplayObjects中的值是与 ListOfComboBoxDisplayObjects 关联的相关值部分中提供的值。在这种情况下,枚举数类型为Values。这些是我为简化示例而创建的任意值。关于绑定,所有绑定操作似乎都正常运行。通常当绑定出现问题时,调试器会将问题输出到Debug输出窗口。在这种情况下,我在重新分配后没有看到任何消息或错误。 -
需要明确的是,当用户选择
Foo或Bar时,绑定工作正常并且已经过双重检查。当用户适当地响应提示时,即使Baz也能正常工作。但是,当操作被取消时,ComboBox 中的 UI 元素不会更新文本,但我确信我的 VM 中的基础值是正确的。 -
我要求的不是值,而是该属性的源代码、类型等。如果您确定问题不仅仅是缺少通知,那么值得尝试准备 @987654321 @。您很好地描述了问题的输入和输出,但没有显示您可能(理论上)犯错的所有关键部分。
-
BindableEnumerationItem和Values是什么?似乎您忘记为Values覆盖Equals,这是比较值的预期行为吗?没有 - 它会比较引用,因此将ComboBox.SelectedValue设置为ListOfComboBoxDisplayObjects中未引用的内容显然不会更改ComboBox的当前选择(因为它找不到项目)。覆盖Equals(和GetHashCodeofc)的Values。