C# 为什么';WPF组合框是否正确反映绑定值?

C# 为什么';WPF组合框是否正确反映绑定值?,c#,wpf,xaml,data-binding,C#,Wpf,Xaml,Data Binding,我有一个组合框,其属性ItemsSource和SelectedValue绑定到一个模型。有时,模型需要将所选项目调整为不同的项目,但当我在模型中执行此操作时,模型值不会反映在视图中,即使SelectedValue已正确设置(使用snoop和SelectionChanged事件处理程序检查) 为了说明这个问题,下面是一个简单的xaml: <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.mic

我有一个组合框,其属性ItemsSource和SelectedValue绑定到一个模型。有时,模型需要将所选项目调整为不同的项目,但当我在模型中执行此操作时,模型值不会反映在视图中,即使SelectedValue已正确设置(使用snoop和SelectionChanged事件处理程序检查)

为了说明这个问题,下面是一个简单的xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
      <ComboBox Height="25" Width="120" SelectedValue="{Binding SelectedValue}" SelectedValuePath="Key" ItemsSource="{Binding PossibleValues}" DisplayMemberPath="Value"/>
   </Grid>
</Window>

以下是模型:

using System.Collections.Generic;
using System.Windows;
using System.ComponentModel;

namespace WpfApplication1
{
   public partial class MainWindow : Window, INotifyPropertyChanged
   {
      int m_selectedValue = 2;
      Dictionary<int, string> m_possibleValues = new Dictionary<int, string>() { { 1, "one" }, { 2, "two" }, { 3, "three" }, {4,"four"} };

      public int SelectedValue
      {
         get { return m_selectedValue; }
         set 
         {
            if (value == 3)
            {
               m_selectedValue = 1;
            }
            else
            {
               m_selectedValue = value;
            }
            PropertyChanged(this, new PropertyChangedEventArgs("SelectedValue"));
         }
      }
      public Dictionary<int, string> PossibleValues
      {
         get { return m_possibleValues; }
         set { m_possibleValues = value; }
      }


      public MainWindow()
      {
         InitializeComponent();
      }

      public event PropertyChangedEventHandler PropertyChanged;
   }
}
使用System.Collections.Generic;
使用System.Windows;
使用系统组件模型;
命名空间WpfApplication1
{
公共部分类主窗口:窗口,INotifyPropertyChanged
{
int m_selectedValue=2;
Dictionary m_possibleValues=新字典(){{1,“一”},{2,“二”},{3,“三”},{4,“四”};
公共整数选择值
{
获取{return m_selectedValue;}
设置
{
如果(值==3)
{
m_selectedValue=1;
}
其他的
{
m_selectedValue=值;
}
PropertyChanged(这是新的PropertyChangedEventArgs(“SelectedValue”);
}
}
公共词典可能值
{
获取{return m_possibleValues;}
设置{m_possibleValues=value;}
}
公共主窗口()
{
初始化组件();
}
公共事件属性更改事件处理程序属性更改;
}
}
我希望行为如下:

  • 最初,选择两个
  • 选择“一”->组合框显示“一”
  • 选择“两个”->组合框显示“两个”
  • 选择“三个”->组合框显示“一个”
  • 选择“四”->组合框显示“四”
  • 但是,在#4中,会显示“三”。为什么?模型中的值已更改为1(“一”),但视图仍显示3(“三”)


    我通过显式更新SelectionChanged事件处理程序中的绑定目标找到了解决方法,但这似乎是错误的。有没有其他方法可以实现这一点?

    在绑定到
    组合框
    控件的
    SelectedValue
    和/或
    SelectedItem
    属性时,我始终无法正确更新控件


    为了解决这个问题,我必须绑定到
    SelectedIndex
    属性。在我的ViewModel中处理“index”属性比较麻烦,但它解决了组合框不更新的问题。

    当您选择一个项目时,绑定引擎将更新模型,并忽略它在调用属性设置程序期间刚刚更改的属性的任何
    属性更改。否则,事情可能会进入无限循环

    系统假定setter不会更改它传递的值。这里的解决方法很简单:在绑定上使用
    Dispatcher.BeginInvoke()
    或设置
    IsAsync=True
    ,以获得所需的行为。然而,我个人强烈反对你这样做。这不仅是因为它引入了一大堆与计时有关的新问题,而且主要是因为它是一个解决一个本来不应该存在的问题的方法

    不要这样做。它不仅适用于WPF:任何更改setter的操作都可能期望它刚刚正确设置的值不会引发异常。更改setter中的值是违反直觉的,可能会在以后影响您。另外,如果应用程序的用户看到组合框忽略了它的选择,这可能会非常令人不安


    如果您不喜欢传递的值,请抛出异常并使用
    Binding.ValidatesOnExceptions
    告诉WPF它是预期的。如果您不希望用户选择此值,首先不要将其放入列表中。如果由于其他业务规则,该项不应该有条件地可用,请动态筛选列表或应用触发器。

    组合框不应该显示模型的当前状态吗?它可能不是直观的,但它是正确的显示。这实际上是一个简化的例子。实际的用例有点复杂,但归结起来是同一个问题。您是否尝试过以两种方式显式地生成SelectedValue?{Binding Path=SelectedValue,Mode=TwoWay}@JacobProffitt Mode默认为TwoWay,但我只是尝试显式设置它,问题仍然存在。我实际上尝试了所有SelectedValue、SelectedItem和SelectedIndex,结果都是一样的。
    IsAsync=True
    有效。阅读描述,我不知道为什么它会这样,因为它不是为了这个,但它确实:)。您提到不鼓励此实现。有什么建议我可以做吗?实际用例是这样的:我有一个预定义数量的值配置文件,我必须尝试近似。这与combobox范例非常匹配,因为用户应该选择一个预定义的值。但是,在某些情况下,我无法达到所选的值,因此为了不误导用户,我喜欢将该值更改为“中间值”。为了补充上述注释,思考此setter所做操作的另一种方式是将其视为“愿望”。如“我希望设置此值,但如果不能,请尽可能接近”,我不同意。拥有“setter”属性的全部目的是保护支持字段(可以公开)。属性应该对值执行检查和验证,并确保其有效。如果不是,抛出异常并不总是一个实际的解决方案。