Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何从PropertyChanged事件中正确重置与组合框关联的值?_C#_Wpf_Combobox_Binding - Fatal编程技术网

C# 如何从PropertyChanged事件中正确重置与组合框关联的值?

C# 如何从PropertyChanged事件中正确重置与组合框关联的值?,c#,wpf,combobox,binding,C#,Wpf,Combobox,Binding,我有一个组合框,它绑定到我的ViewModel上的一个属性(来自“VM”上的hear)。当用户在组合框上进行选择时,它会正确更新我的VM中绑定的属性。在我的UI代码中,我已经订阅了VM上的PropertyChanged事件 正如它应该表现的那样,当用户在组合框中进行选择时,myPropertyChanged事件在my UI后端代码中正确执行。当UI代码捕捉到此属性的更改时,在某些选择条件下,我需要停止进程并请求用户提供其他信息。我从UI向他们发送一个对话框。如果他们取消对话框,我将重置VM中与组

我有一个
组合框
,它绑定到我的ViewModel上的一个属性(来自“VM”上的hear)。当用户在
组合框
上进行选择时,它会正确更新我的VM中绑定的属性。在我的UI代码中,我已经订阅了VM上的
PropertyChanged
事件

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

这就是我观察到的。当用户取消操作时,my VM属性将设置为新值。但是,
组合框
仍然显示现在已更改的原始条目的文本值。如何从我的
属性更改
事件中强制组合框更新自身?在这种情况下,我认为这只是引用绑定集合中的文本数据的文本问题或数字索引更改。VM中的数据正确,但组合框的显示值错误

示例

组合框详细信息

    <ComboBox
        ItemsSource="{Binding ListOfComboBoxDisplayObjects}"
        SelectedValue="{Binding MySelectionIsAnEnumeration}"
        DisplayMemberPath="Text"
        SelectedValuePath="EnumerationValue"
        Height="27" />
MySelectionanEnumeration定义(来自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 )));
            }
        }
    }
与ListOfComboxDisplayObjects关联的相关值

    <ComboBox
        ItemsSource="{Binding ListOfComboBoxDisplayObjects}"
        SelectedValue="{Binding MySelectionIsAnEnumeration}"
        DisplayMemberPath="Text"
        SelectedValuePath="EnumerationValue"
        Height="27" />
这些值在VM的ctor中生成。它们在整个应用程序中都是固定的

项目#1

  • 文字:“这是一个Foo!”
  • Value:Values.Foo
第2项:

  • 文字:“嗨,我是酒吧。”
  • 值:Values.Bar
第3项:

  • 文字:“我是Baz。我需要问一个问题才能使用。”
  • Value:Values.Baz
属性更改事件-从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.myselectionanenumeration
值实际上正在更改为
value.Foo
的正确值。但是,完成后,
组合框仍然显示“这是Baz。我需要问一个问题才能使用”。这显然是与
value.Baz
关联的显示值

如何更新基础VM属性和组合框上的显示文本,以正确显示当前存储在
VM.mySelectionAnEnumeration
中的值

编辑#2

下面是我在组合框和列表框的可观察集合中使用的
BindableEnumerationItem
的代码。在我的整个应用程序中,在更简单的情况下都使用了这种方法,没有引起任何问题。请注意,这是我的实际代码,未经修改。我没有重命名任何东西。我的组合框可以绑定到类型安全属性的每个
属性,并且
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"));
        }
    }
}
公共类BindableEnumerationItem:INotifyPropertyChanged
{
公共事件PropertyChangedEventHandler PropertyChanged=委托{};
私人信托基金项目;
公共BindableEnumerationItem(T项,字符串显示文本)
{
_项目=项目;
_displayText=displayText;
}
私有字符串_displayText;
公共字符串显示文本
{
获取{return\u displayText;}
设置
{
如果(值!=\u显示文本)
{
_显示文本=值;
PropertyChanged(这是新的PropertyChangedEventArgs(“DisplayText”);
}
}
}
公共交通项目
{
获取{return\u item;}
设置
{
_项目=价值;
财产变更(这是指新的财产变更项(“项目”);
}
}
}

创建一个扩展,将命令从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" />


如果视图未更新绑定,则表示缺少通知或绑定错误。能否显示
ListOfComboxDisplayObjects
及其类型和
mySelectionAnEnumeration
?@Sinatr,
ListOfComboxDisplayObjects
中的值是与ListOfComboxDisplayObjects关联的相关值一节中提供的值。在这种情况下,枚举数类型为
。这些是我为简化示例而创建的任意值。关于绑定,所有绑定操作似乎都正常运行。通常,当绑定出现问题时,调试器会将问题输出到“调试输出”窗口。在这种情况下,在重新分配后,我没有看到任何消息或错误。更清楚的是,当用户选择
Foo
Bar
时,绑定工作正常,并且已被双重检查。当用户正确响应提示时,即使是
Baz
也能正常工作。但是,当操作被取消时,ComboBox中的UI元素不会更新文本,但我确信我的VM中的基础值是正确的。我不是在要求值,而是该属性的源代码、其类型等。如果您确定问题不仅仅是缺少通知,那么很值得尝试准备。你们很好地描述了问题的输入和输出,但并没有展示所有你们可以(理论上)理解的关键部分