首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将WPF ComboBox绑定到自定义列表

将WPF ComboBox绑定到自定义列表
EN

Stack Overflow用户
提问于 2009-02-18 14:06:14
回答 4查看 633.8K关注 0票数 202

我有一个似乎不更新SelectedItem/SelectedValue的ComboBox。

ComboBox ItemsSource绑定到ViewModel类上的一个属性,该类将一组RAS电话簿条目作为CollectionView列出。然后,我(在不同的时间)将SelectedItemSelectedValue绑定到ViewModel的另一个属性。我已经在save命令中添加了一个MessageBox来调试数据绑定设置的值,但是没有设置SelectedItem/SelectedValue绑定。

ViewModel类如下所示:

代码语言:javascript
复制
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看起来像这样:

代码语言:javascript
复制
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
    DisplayMemberPath="Name"
    SelectedValuePath="Name"
    SelectedValue="{Binding Path=PhonebookEntry}" />

我只对ComboBox中显示的实际字符串值感兴趣,而对对象的任何其他属性都不感兴趣,因为这是我想要建立VPN连接时需要传递给RAS的值,因此DisplayMemberPathSelectedValuePath都是ConnectionViewModel的Name属性。ComboBox位于应用于窗口上的ItemsControlDataTemplate中,该窗口的DataContext已设置为ViewModel实例。

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

在数据绑定ComboBox方面,我错过了什么?我做了很多搜索,似乎找不到我做错了什么。

这就是我看到的行为,但由于某种原因,它在我的特定上下文中不起作用。

我有一个MainWindowViewModel,它的CollectionView为ConnectionViewModels。在MainWindowView.xaml文件代码隐藏中,我将DataContext设置为MainWindowViewModel。MainWindowView.xaml有一个绑定到ConnectionViewModels集合的ItemsControl。我有一个包含ComboBox和一些其他TextBoxes的DataTemplate。使用Text="{Binding Path=ConnectionName}"将TextBoxes直接绑定到ConnectionViewModel的属性。

代码语言:javascript
复制
public class ConnectionViewModel : ViewModelBase
{
    public string Name { get; set; }
    public string Password { get; set; }
}

public class MainWindowViewModel : ViewModelBase
{
    // List<ConnectionViewModel>...
    public CollectionView Connections { get; set; }
}

XAML代码隐藏:

代码语言:javascript
复制
public partial class Window1
{
    public Window1()
    {
        InitializeComponent();
        DataContext = new MainWindowViewModel();
    }
}

,然后是XAML:

代码语言:javascript
复制
<DataTemplate x:Key="listTemplate">
    <Grid>
        <ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
            DisplayMemberPath="Name"
            SelectedValuePath="Name"
            SelectedValue="{Binding Path=PhonebookEntry}" />
        <TextBox Text="{Binding Path=Password}" />
    </Grid>
</DataTemplate>

<ItemsControl ItemsSource="{Binding Path=Connections}"
    ItemTemplate="{StaticResource listTemplate}" />

所有TextBoxes都正确绑定,并且数据在它们和ViewModel之间移动没有问题。只是ComboBox不起作用。

您关于PhonebookEntry类的假设是正确的。

我所做的假设是,我的DataTemplate使用的DataContext是通过绑定层次结构自动设置的,这样我就不必为ItemsControl中的每个项显式设置它。这对我来说似乎有点傻。

基于上面的例子,下面是一个演示这个问题的测试实现。

XAML:

代码语言:javascript
复制
<Window x:Class="WpfApplication7.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <DataTemplate x:Key="itemTemplate">
            <StackPanel Orientation="Horizontal">
                <TextBox Text="{Binding Path=Name}" Width="50" />
                <ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
                    DisplayMemberPath="Name"
                    SelectedValuePath="Name"
                    SelectedValue="{Binding Path=PhonebookEntry}"
                    Width="200"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ItemsControl ItemsSource="{Binding Path=Connections}"
            ItemTemplate="{StaticResource itemTemplate}" />
    </Grid>
</Window>

代码隐藏

代码语言:javascript
复制
namespace WpfApplication7
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    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<PhoneBookEntry> list = new List<PhoneBookEntry>
                                             {
                                                 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<ConnectionViewModel> connections = new List<ConnectionViewModel>
                                                          {
                                                              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

绑定到DataContext.PhonebookEntries的..Items ->

....Item -> DataContext = PhonebookEntry (隐式关联)

我不知道这是否能更好地解释我的假设。

为了确认我的假设,将TextBox的绑定更改为

代码语言:javascript
复制
<TextBox Text="{Binding Mode=OneWay}" Width="50" />

这将显示TextBox绑定根(我正在将其与DataContext进行比较)是ConnectionViewModel实例。

EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/561166

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档