C# SelectedValue在代码中设置时不更新

C# SelectedValue在代码中设置时不更新,c#,wpf,mvvm,C#,Wpf,Mvvm,我知道以前有人问过这个问题,但对我来说似乎什么都不管用 我有一个wpf桌面应用程序 我有这个组合框: <ComboBox ItemsSource="{Binding Users, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Value.Login" SelectedValue="{Binding SelectedManagerUser, Mode=TwoWay,UpdateSou

我知道以前有人问过这个问题,但对我来说似乎什么都不管用

我有一个wpf桌面应用程序

我有这个组合框:

<ComboBox ItemsSource="{Binding Users, Mode=TwoWay,  UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Value.Login"
   SelectedValue="{Binding SelectedManagerUser, 
   Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"  
   SelectedValuePath="Value"  
   IsSynchronizedWithCurrentItem="True"  />
我知道添加新项目是因为-

  • 我可以在下拉列表中看到它
  • 我在代码中设置了一个断点并进行了检查
  • 组合框只显示一个空值

    还有什么我可以试试的吗


    谢谢

    您的SelectedManagerUser属性应更改为此。SelectedManagerUser属性设置为新值,但您不会引发该事件,因此UI不会更新

        private UserRecord _selectedManagerUser;
        public UserRecord SelectedManagerUser 
        { 
            get
            {
                return _selectedManagerUser;
            }
            set
            {
                _selectedManagerUser = value;
                RaisePropertyChanged("SelectedManagerUser");
            }
        }
    

    我不确定你这边出了什么问题,但看看一个可行的解决方案可能会有所帮助

    XAML:

    
    
    代码隐藏:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            Loaded += WindowLoaded;
    
            var vm = new ViewModel();
            vm.Users.Add("u1", new UserRecord { Name = "User 1" });
            vm.Users.Add("u2", new UserRecord { Name = "User 2" });
            vm.Users.Add("u3", new UserRecord { Name = "User 3" });
            DataContext = vm;
        }
    
        private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            // make sure it works after DataContext was set
            var vm = (ViewModel)DataContext;
            vm.SelectedUser = vm.Users["u2"];
        }
    }
    
    public class UserRecord
    {
        public string Name { get; set; }
    }
    
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        public Dictionary<string, UserRecord> Users { get; }
            = new Dictionary<string, UserRecord>();
    
        private UserRecord selectedUser;
        public UserRecord SelectedUser
        {
            get { return selectedUser; }
            set
            {
                selectedUser = value;
                PropertyChanged?.Invoke(this,
                    new PropertyChangedEventArgs(nameof(SelectedUser)));
            }
        }
    }
    
    公共部分类主窗口:窗口
    {
    公共主窗口()
    {
    初始化组件();
    加载+=窗口加载;
    var vm=new ViewModel();
    Add(“u1”,新用户记录{Name=“User 1”});
    Add(“u2”,新用户记录{Name=“User 2”});
    Add(“u3”,新用户记录{Name=“User 3”});
    DataContext=vm;
    }
    已加载私有void窗口(对象发送器,RoutedEventArgs e)
    {
    //确保它在设置DataContext后工作
    var vm=(ViewModel)DataContext;
    vm.SelectedUser=vm.Users[“u2”];
    }
    }
    公共类用户记录
    {
    公共字符串名称{get;set;}
    }
    公共类视图模型:INotifyPropertyChanged
    {
    公共事件属性更改事件处理程序属性更改;
    公共字典用户{get;}
    =新字典();
    私人用户记录选择用户;
    公共用户记录选择用户
    {
    获取{return selectedUser;}
    设置
    {
    selectedUser=值;
    PropertyChanged?调用(此,
    新属性ChangedEventArgs(名称(SelectedUser));
    }
    }
    }
    
    Nuget
    下载
    Prism
    ,并从
    BindableBase
    继承您的类

    使用后:

    private UserRecord selectedManagerUser;
    
    public UserRecord SelectedManagerUser
    {
        get { return this.selectedManagerUser; }
        set { this.SetProperty(ref this.selectedManagerUser, value); }
    }
    

    两种情况中的一种会导致这种情况。首先,可能是因为您没有将
    SelectedManagerUser
    设置为
    UserRecord
    的一个实例,而该实例不在字典中,或者字典仍然不能用于数据绑定。让我把它们都盖上

    使用
    itemsource
    SelectedItem
    绑定时,如果希望
    SelectedItem
    更改反映在UI中,则必须将其设置为可在
    itemsource
    中找到的实例。默认情况下,控件将在源中查找与选定项在引用上相等的项。我99%确信它将使用
    IEquatable
    而不是参考检查您的项目是否实现了它

    如果这不是你的问题,那是因为字典不适合数据绑定

    字典对于数据绑定来说很糟糕。太糟糕了。如果需要键控集合,并且希望与之绑定,请创建自定义集合。通过一些额外的工作,TItem可以实现INPC(使密钥为只读,tho),集合可以实现INCC。非常适合装订。我为什么要提到这一点?继续读

    您的问题是,在组合框中,
    SelectedItem
    实际上是
    KeyValuePair
    类型,而不是
    UserRecord
    。因此绑定将不起作用。如果您获取Snoop的副本并在运行时检查绑定,您将看到这一点

    问题是控件不知道jack Shuck关于字典的事。它只知道
    IEnumerable
    Dictionary
    实现了
    IEnumerable
    ,因此控件为每个键值对创建一个项。SelectedItem也是一个键值对。因此,当您将其绑定到类型为
    UserRecord
    的属性时,是的,它可以使用SelectedValuePath正确设置该值,但它不能(不)[忍者编辑:除非这种行为在过去几年中发生了变化:/]在视图模型中设置值时,迭代可枚举项以找到正确的键值对

    如果
    UserRecord
    的键值是该类型中的属性,那么一定要为其创建KeyedCollection
    KeyedCollection
    实现“IEnumerable”,因此它可以无缝地与绑定一起工作。如果不是,则将其包装在代理中,或添加属性


    当我说“用代理包起来”的时候,任何说“什么,像KeyValuePair?”的人我都会在互联网上打你。代理将成为您绑定所依据的值。不要把时间浪费在这篇
    SelectedValuePath
    废话上。直接与代理合作。当您需要值时,请在最后一刻提取它,而不是在绑定执行后立即提取。

    什么是
    temp
    ?您好,很抱歉,是的,temp是我创建的新键,是从文本框派生的。同样,密钥是有效的。我猜问题是您的新密钥/值不在用户集合中。您必须记住,combobox不会收到关于用户集合中任何新项目的通知,只有在
    Users
    @Pikoh中设置了一个新集合时才会收到通知,就像我在问题中所说的那样,它会被填充,这就是我发布问题的原因。酷,有助于现在问题的全貌。我认为您的IsSynchronizedWithCurrentItem可能会因为绑定到字典而混淆。尝试删除它以查看是否出现新条目。这可能足够了,不过你可能需要采取非字典的方式。金,谢谢。是我的错,我刚刚简写了那处房产的cod。我有你有的。但是谢谢如果你的.NET版本不是太旧,
    RaisePropertyChanged(nameof(SelectedManagerUser))
    也可以工作谢谢必须弹出,但在返回时仍会弹出嗨,我回来了。我现在来看看这个。我会采用你的代码,然后重新开始我的工作。我一定是做错了什么。这对我来说确实有效,但对UserRecord有很多不同的
    <ComboBox ItemsSource="{Binding Users}"
              DisplayMemberPath="Value.Name"
              SelectedValue="{Binding SelectedUser}"  
              SelectedValuePath="Value" />
    
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            Loaded += WindowLoaded;
    
            var vm = new ViewModel();
            vm.Users.Add("u1", new UserRecord { Name = "User 1" });
            vm.Users.Add("u2", new UserRecord { Name = "User 2" });
            vm.Users.Add("u3", new UserRecord { Name = "User 3" });
            DataContext = vm;
        }
    
        private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            // make sure it works after DataContext was set
            var vm = (ViewModel)DataContext;
            vm.SelectedUser = vm.Users["u2"];
        }
    }
    
    public class UserRecord
    {
        public string Name { get; set; }
    }
    
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        public Dictionary<string, UserRecord> Users { get; }
            = new Dictionary<string, UserRecord>();
    
        private UserRecord selectedUser;
        public UserRecord SelectedUser
        {
            get { return selectedUser; }
            set
            {
                selectedUser = value;
                PropertyChanged?.Invoke(this,
                    new PropertyChangedEventArgs(nameof(SelectedUser)));
            }
        }
    }
    
    private UserRecord selectedManagerUser;
    
    public UserRecord SelectedManagerUser
    {
        get { return this.selectedManagerUser; }
        set { this.SetProperty(ref this.selectedManagerUser, value); }
    }