当前位置:  开发笔记 > 编程语言 > 正文

将WPF ComboBox绑定到自定义列表

如何解决《将WPFComboBox绑定到自定义列表》经验,为你挑选了3个好方法。

我有一个似乎没有更新SelectedItem/SelectedValue的ComboBox.

组合框ItemsSource绑定到上列出一串RAS电话簿条目作为一个的CollectionView的视图模型类的属性.然后,我必然(在不同的时间)两个SelectedItemSelectedValue到视图模型的另一个属性.我在save命令中添加了一个MessageBox来调试数据绑定设置的值,但是没有设置SelectedItem/ SelectedValuebinding.

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连接,因此价值DisplayMemberPathSelectedValuePath都的名称属性ConnectionViewModel.ComboBox DataTemplate应用于ItemsControl一个Window,其DataContext已设置为ViewModel实例.

ComboBox正确显示项目列表,我可以在UI中选择一个没有问题.但是,当我从命令中显示消息框时,PhonebookEntry属性仍然具有初始值,而不是ComboBox中的选定值.其他TextBox实例正在更新并在MessageBox中显示.

使用数据绑定ComboBox我错过了什么?我做了很多搜索,似乎找不到任何我做错的事.


这是我所看到的行为,但是在我的特定情况下,它不能用于某种原因.

我有一个MainWindowViewModel,它有一个CollectionViewConnectionViewModel.在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;
            IList list = 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实例.



1> Kjetil Watne..:

您将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()
        {
            IList list = 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仅指定所选项目和显示项目的成员.


我可以确认将`ItemsSource`属性绑定到的集合更改为只读集合使其工作.在我的情况下,我不得不将它从`ObservableCollection`更改为`ReadOnlyObservableCollection`.坚果.这是.NET 3.5 - 不确定它是否在4.0中修复

2> 小智..:

将数据绑定到ComboBox

List ListData = 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; } 
}


`Id`和`Value`必须是*属性*,而不是类字段,如:`public class ComboData {public int Id {get; 组; } public string Value {get; 组; }
你们...太棒了

3> CyberMonk..:

我最初看起来似乎是一个相同的问题,但结果是由于NHibernate/WPF兼容性问题.问题是由WPF检查对象相等性的方式引起的.通过使用SelectedValue和SelectedValuePath属性中的对象ID属性,我能够使我的东西工作.


有关详细信息,请参阅Chester的博客文章,WPF ComboBox - SelectedItem,SelectedValue和SelectedValuePath with NHibernate.

推荐阅读
罗文彬2502852027
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有