我有一个似乎没有更新SelectedItem/SelectedValue的ComboBox.
组合框ItemsSource绑定到上列出一串RAS电话簿条目作为一个的CollectionView的视图模型类的属性.然后,我必然(在不同的时间)两个SelectedItem
或SelectedValue
到视图模型的另一个属性.我在save命令中添加了一个MessageBox来调试数据绑定设置的值,但是没有设置SelectedItem
/ SelectedValue
binding.
ViewModel类看起来像这样:
public ConnectionViewModel { private readonly CollectionView _phonebookEntries; private string _phonebookeEntry; public CollectionView PhonebookEntries { get { return _phonebookEntries; } } public string PhonebookEntry { get { return _phonebookEntry; } set { if (_phonebookEntry == value) return; _phonebookEntry = value; OnPropertyChanged("PhonebookEntry"); } } }
_phonebookEntries集合正在构造函数中从业务对象初始化.ComboBox XAML看起来像这样:
我只在下拉列表中显示的实际字符串值感兴趣的对象,因为这不是任何其他属性是我需要跨到RAS通过时,我想使VPN连接,因此价值DisplayMemberPath
和SelectedValuePath
都的名称属性ConnectionViewModel.ComboBox DataTemplate
应用于ItemsControl
一个Window,其DataContext已设置为ViewModel实例.
ComboBox正确显示项目列表,我可以在UI中选择一个没有问题.但是,当我从命令中显示消息框时,PhonebookEntry属性仍然具有初始值,而不是ComboBox中的选定值.其他TextBox实例正在更新并在MessageBox中显示.
使用数据绑定ComboBox我错过了什么?我做了很多搜索,似乎找不到任何我做错的事.
这是我所看到的行为,但是在我的特定情况下,它不能用于某种原因.
我有一个MainWindowViewModel,它有一个CollectionView
ConnectionViewModel.在MainWindowView.xaml文件代码隐藏中,我将DataContext设置为MainWindowViewModel.MainWindowView.xaml ItemsControl
绑定到ConnectionViewModel的集合.我有一个DataTemplate,它包含ComboBox以及其他一些TextBox.TextBoxes使用直接绑定到ConnectionViewModel的属性Text="{Binding Path=ConnectionName}"
.
public class ConnectionViewModel : ViewModelBase { public string Name { get; set; } public string Password { get; set; } } public class MainWindowViewModel : ViewModelBase { // List... public CollectionView Connections { get; set; } }
XAML代码隐藏:
public partial class Window1 { public Window1() { InitializeComponent(); DataContext = new MainWindowViewModel(); } }
那么XAML:
TextBoxes都正确绑定,数据在它们和ViewModel之间移动没有任何问题.它只是ComboBox无法正常工作.
关于PhonebookEntry类的假设是正确的.
我所做的假设是我的DataTemplate使用的DataContext是通过绑定层次结构自动设置的,因此我不必为每个项目显式设置它ItemsControl
.这对我来说似乎有点傻.
这是一个基于上面的例子演示该问题的测试实现.
XAML:
在后台代码:
namespace WpfApplication7 { ////// Interaction logic for Window1.xaml /// public partial class Window1 : Window { public Window1() { InitializeComponent(); DataContext = new MainWindowViewModel(); } } public class PhoneBookEntry { public string Name { get; set; } public PhoneBookEntry(string name) { Name = name; } } public class ConnectionViewModel : INotifyPropertyChanged { private string _name; public ConnectionViewModel(string name) { _name = name; IListlist = new List { new PhoneBookEntry("test"), new PhoneBookEntry("test2") }; _phonebookEntries = new CollectionView(list); } private readonly CollectionView _phonebookEntries; private string _phonebookEntry; public CollectionView PhonebookEntries { get { return _phonebookEntries; } } public string PhonebookEntry { get { return _phonebookEntry; } set { if (_phonebookEntry == value) return; _phonebookEntry = value; OnPropertyChanged("PhonebookEntry"); } } public string Name { get { return _name; } set { if (_name == value) return; _name = value; OnPropertyChanged("Name"); } } private void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged; } public class MainWindowViewModel { private readonly CollectionView _connections; public MainWindowViewModel() { IList connections = new List { new ConnectionViewModel("First"), new ConnectionViewModel("Second"), new ConnectionViewModel("Third") }; _connections = new CollectionView(connections); } public CollectionView Connections { get { return _connections; } } } }
如果您运行该示例,您将获得我正在谈论的行为.TextBox在编辑时更新其绑定,但ComboBox没有.非常令人困惑的看到我真正做的唯一事情就是引入一个父ViewModel.
我目前正在努力工作的印象是绑定到DataContext的子项的项目将该子项作为其DataContext.我找不到任何可以通过这种方式清除它的文档.
也就是说,
Window - > DataContext = MainWindowViewModel
..Items - >绑定到DataContext.PhonebookEntries
.... Item - > DataContext = PhonebookEntry(隐式关联)
我不知道这是否能更好地解释我的假设(?).
要确认我的假设,请更改TextBox的绑定
这将显示TextBox绑定根(我与DataContext进行比较)是ConnectionViewModel实例.
您将DisplayMemberPath和SelectedValuePath设置为"Name",因此我假设您有一个具有公共属性Name的PhoneBookEntry类.
您是否已将DataContext设置为ConnectionViewModel对象?
我复制了你的代码并做了一些小修改,似乎工作正常.我可以设置viewmodels PhoneBookEnty属性和组合框中的选定项目更改,我可以更改组合框中的选定项目,并正确设置视图模型PhoneBookEntry属性.
这是我的XAML内容:
这是我的代码隐藏:
namespace WpfApplication6 { ////// Interaction logic for Window1.xaml /// public partial class Window1 : Window { public Window1() { InitializeComponent(); ConnectionViewModel vm = new ConnectionViewModel(); DataContext = vm; } private void Button_Click(object sender, RoutedEventArgs e) { ((ConnectionViewModel)DataContext).PhonebookEntry = "test"; } } public class PhoneBookEntry { public string Name { get; set; } public PhoneBookEntry(string name) { Name = name; } public override string ToString() { return Name; } } public class ConnectionViewModel : INotifyPropertyChanged { public ConnectionViewModel() { IListlist = new List (); list.Add(new PhoneBookEntry("test")); list.Add(new PhoneBookEntry("test2")); _phonebookEntries = new CollectionView(list); } private readonly CollectionView _phonebookEntries; private string _phonebookEntry; public CollectionView PhonebookEntries { get { return _phonebookEntries; } } public string PhonebookEntry { get { return _phonebookEntry; } set { if (_phonebookEntry == value) return; _phonebookEntry = value; OnPropertyChanged("PhonebookEntry"); } } private void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged; } }
编辑:杰夫斯的第二个例子似乎没有用,这对我来说似乎有点奇怪.如果我将ConnectionViewModel上的PhonebookEntries属性更改为ReadOnlyCollection类型,则组合框上的SelectedValue属性的TwoWay绑定可以正常工作.
也许CollectionView存在问题?我注意到输出控制台中有一个警告:
System.Windows.Data警告:50:不完全支持直接使用CollectionView.虽然效率低下,但基本功能仍然有效,但高级功能可能会遇到已知错误.考虑使用派生类来避免这些问题.
Edit2(.NET 4.5): DropDownList的内容可以基于ToString()而不是DisplayMemberPath,而DisplayMemberPath仅指定所选项目和显示项目的成员.
将数据绑定到ComboBox
ListListData = new List (); ListData.Add(new ComboData { Id = "1", Value = "One" }); ListData.Add(new ComboData { Id = "2", Value = "Two" }); ListData.Add(new ComboData { Id = "3", Value = "Three" }); ListData.Add(new ComboData { Id = "4", Value = "Four" }); ListData.Add(new ComboData { Id = "5", Value = "Five" }); cbotest.ItemsSource = ListData; cbotest.DisplayMemberPath = "Value"; cbotest.SelectedValuePath = "Id"; cbotest.SelectedValue = "2";
ComboData看起来像:
public class ComboData { public int Id { get; set; } public string Value { get; set; } }
我最初看起来似乎是一个相同的问题,但结果是由于NHibernate/WPF兼容性问题.问题是由WPF检查对象相等性的方式引起的.通过使用SelectedValue和SelectedValuePath属性中的对象ID属性,我能够使我的东西工作.
有关详细信息,请参阅Chester的博客文章,WPF ComboBox - SelectedItem,SelectedValue和SelectedValuePath with NHibernate.