如何从PropertyChanged事件中正确重置与ComboBox关联的值?

时间:2017-01-31 13:12:27

标签: c# wpf combobox binding

我有ComboBox绑定到我的ViewModel上的属性(来自于#34; VM")当用户在ComboBox上进行选择时,它会正确更新我的VM中的绑定属性。在我的UI代码中,我已经订阅了我的VM上的PropertyChanged事件。

正如它应该表现的那样,当用户在ComboBox中进行选择时,我的PropertyChanged事件在我的UI后端代码中正确执行。当UI代码捕获到此属性的更改时,在某些选择条件下,我需要暂停该过程并请求用户提供其他信息。在UI中,我向他们发送了一个对话框。如果他们取消了对话框,我会重置与ComboBox控件SelectedValue关联的VM中的值。

这是我所观察到的。当用户取消操作时,我的VM属性被设置为新值。但是,ComboBox仍显示现在已更改的原始条目的文本值。如何强制ComboBox在我的PropertyChanged事件中更新自己?在这种情况下,我认为它只是一个文本问题或数字索引更改引用绑定集合中的文本数据。虚拟机中的数据是正确的,但ComboBox的显示值是错误的。

示例

ComboBox详细信息

    <ComboBox
        ItemsSource="{Binding ListOfComboBoxDisplayObjects}"
        SelectedValue="{Binding MySelectionIsAnEnumeration}"
        DisplayMemberPath="Text"
        SelectedValuePath="EnumerationValue"
        Height="27" />

对于虚拟机上的罗嗦属性感到抱歉,但这可以解释发生了什么。我的ListOfComboBoxDisplayObjects集合表示存储在SelectedValuePath内的路径中的一组枚举器值。每个值的描述性文本都是从ListOfComboBoxDisplayObjects中提取的, 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))); } } } 是为UI严格创建的特殊列表。这基本上将枚举值与有意义的描述配对。

ListOfComboBoxDisplayObjects定义(来自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 )));
            }
        }
    }

MySelectionIsAnEnumeration定义(来自VM内)

*编辑#1:添加此代码定义。

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;
            }
        }

与ListOfComboBoxDisplayObjects相关的相关值

这些值是在VM的ctor中生成的。它们在整个应用程序中得到修复。

项目#1

  • 文字:&#34;这是一个Foo!&#34;
  • 价值:Values.Foo

项目#2:

  • 文字:&#34;嗨,我是吧。&#34;
  • 价值:Values.Bar

项目#3:

  • 文字:&#34;这是Baz。在使用之前我需要问一个问题。&#34;
  • 价值:Values.Baz

PropertyChanged事件 - 来自UI后端

VM.MySelectionIsAnEnumeration

执行上面的代码后,我观察到的是当用户取消Value.Foo内的操作时,AskAQuestionAndGetAResult()值确实会更改为ComboBox的正确值。但是,在完成后Value.Baz仍会读取&#34;这是Baz。在使用之前我需要问一个问题。&#34; ,这显然是与CombobBox相关联的显示值。

如何更新基础VM属性和VM.MySelectionIsAnEnumeration上的显示文本,以正确显示现在存储在BindableEnumerationItem中的值?

编辑#2

下面是我在我的Observable Collections中用于comboxes和列表框的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")); } } } 是描述符文本。

double c = add(1.2 + 2.2 + 3.3);

1 个答案:

答案 0 :(得分:0)

创建一个扩展,将命令从xaml中的viewmodel连接到选择器,在本例中是选择器。

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;
        }
    }
}

在viewmodel中创建处理值已更改事件的命令。

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;
                    }
                });
    }
}

然后使用该扩展名绑定。 ext是扩展名的命名空间。

<ComboBox
    ItemsSource="{Binding ListOfComboBoxDisplayObjects}"
    SelectedValue="{Binding MySelectionIsAnEnumeration}"
    DisplayMemberPath="Text"
    SelectedValuePath="EnumerationValue"
    ext:Extensions.SelectionChangedCommand="{Binding EnumerationValueChangedCommand}"
    Height="27" />