【问题标题】:Winforms ComboBox DataBinding DisplayMember to SubObject PropertyWinforms ComboBox DataBinding DisplayMember 到 SubObject 属性
【发布时间】:2012-12-05 13:39:57
【问题描述】:

我搜索了 2 小时或更长时间,但找不到答案。所以我在这里试试:

我想知道如何(以及是否可以做到)我可以将模型列表数据绑定到 WinForms 组合框,并使用模型属性的属性(即在列表中)作为 DisplayMember 吗?在此处查看代码:

public partial class Form1 : Form
{
    private List<UserDataModel> userData = new List<UserDataModel>();

    public Form1()
    {
        InitializeComponent();

        MyInit();
    }

    public void MyInit()
    {
        var userDataModel1 = new UserDataModel();
        userDataModel1.Name = "Mike";
        userDataModel1.Phone = "555-666";
        userDataModel1.Home = new HomeDataModel();
        userDataModel1.Home.StreetName = "MikeStreet";
        userDataModel1.Home.GeoLocationX = 111;
        userDataModel1.Home.GeoLocationY = 222;

        var userDataModel2 = new UserDataModel();
        userDataModel2.Name = "Jonathan";
        userDataModel2.Phone = "777-888";
        userDataModel2.Home = new HomeDataModel();
        userDataModel2.Home.StreetName = "JonathanStreet";
        userDataModel2.Home.GeoLocationX = 333;
        userDataModel2.Home.GeoLocationY = 444;

        userData.Add(userDataModel1);
        userData.Add(userDataModel2);

        // This works as usually:
        /*
        comboBox1.DisplayMember = "Name";
        comboBox1.ValueMember = "Home";
        comboBox1.DataSource = userData;
        */

        // But this works not (either with comboBox1.DataBindings.Add() nor with BindingSource):
        comboBox1.DisplayMember = "Home.StreetName";
        comboBox1.ValueMember = "Home";
        comboBox1.DataSource = userData;

        // To drive me crazy, THAT shit works:
        textBox1.DataBindings.Add("Text", userData, "Home.StreetName");

        /*
        So how can i use a String-Property of a SubObject as ComboBox-DisplayMember ???

        BTW: To rebuild the sample, you only need a normal Forms Application and
        then drop a ComboBox and a TextBox on it. Copy that code here, and run it.
        */
    }
}

internal sealed class UserDataModel
{
    public string Name { get; set; }
    public string Phone { get; set; }
    public HomeDataModel Home { get; set; }
}

internal sealed class HomeDataModel
{
    public string StreetName { get; set; }
    public int GeoLocationX { get; set; }
    public int GeoLocationY { get; set; }
}

【问题讨论】:

  • 您希望看到的 ValueMember 是什么?
  • 作为 ValueMember,我使用 Home 本身。因为 ValueMember = "Home" 而不是 ValueMember = "Home.GeoLocationX" ,例如

标签: c# data-binding properties combobox


【解决方案1】:

只需在您的代码中添加一个方法(实际上是事件),它就可以工作了。

public partial class Form1 : Form
{
    private List<UserDataModel> userData = new List<UserDataModel>();
    public Form1()
    {
        InitializeComponent();

        MyInit();
    }

    public void MyInit()
    {
        var userDataModel1 = new UserDataModel();
        userDataModel1.Name = "Mike";
        userDataModel1.Phone = "555-666";
        userDataModel1.Home = new HomeDataModel();
        userDataModel1.Home.StreetName = "MikeStreet";
        userDataModel1.Home.GeoLocationX = 111;
        userDataModel1.Home.GeoLocationY = 222;

        var userDataModel2 = new UserDataModel();
        userDataModel2.Name = "Jonathan";
        userDataModel2.Phone = "777-888";
        userDataModel2.Home = new HomeDataModel();
        userDataModel2.Home.StreetName = "JonathanStreet";
        userDataModel2.Home.GeoLocationX = 333;
        userDataModel2.Home.GeoLocationY = 444;

        userData.Add(userDataModel1);
        userData.Add(userDataModel2);

        // This works as usually:
        /*
        comboBox1.DisplayMember = "Name";
        comboBox1.ValueMember = "Home";
        comboBox1.DataSource = userData;
        */

        // But this works not (either with comboBox1.DataBindings.Add() nor with BindingSource):
        comboBox1.DisplayMember = "Home.StreetName";
        comboBox1.ValueMember = "Home";
        comboBox1.DataSource = userData;

        // To drive me crazy, THAT shit works:
        textBox1.DataBindings.Add("Text", userData, "Home.StreetName");

        /*
        So how can i use a String-Property of a SubObject as ComboBox-DisplayMember ???

        BTW: To rebuild the sample, you only need a normal Forms Application and
        then drop a ComboBox and a TextBox on it. Copy that code here, and run it.
        */
    }

    // To add this method - follow to my instructions below
    private void ComboBoxFormat(object sender, ListControlConvertEventArgs e)
    {
        e.Value = ((UserDataModel)e.ListItem).Home.StreetName;
    }
}

internal sealed class UserDataModel
{
    public string Name { get; set; }
    public string Phone { get; set; }
    public HomeDataModel Home { get; set; }
}

internal sealed class HomeDataModel
{
    public string StreetName { get; set; }
    public int GeoLocationX { get; set; }
    public int GeoLocationY { get; set; }
}

要创建此方法(事件),请在 [设计] 模式下转到您的表单,右键单击组合框 -> 属性。

在属性窗口的顶部,点击事件(闪电图标),

在下面的事件列表中(在 Property Changed 下)查找 Format 并在其中键入一些事件名称,例如:ComboBoxFormat,然后按 Enter。 就是这样;)

【讨论】:

    【解决方案2】:

    Here 是一个类似的问题。在标记的答案中,您可以看到他们在ComboBox 上设置了Form 的BindingContext,这似乎对他们有用...

    //...
    comboBox1.BindingContext = this.BindingContext;
    

    希望对您有所帮助...

    【讨论】:

    • 嗨,与绑定上下文无关(我认为)。我试过了,确实可以肯定,组合框无论如何都使用表单 bindingcontext(确实如此):
    【解决方案3】:

    好的,我已经让 DisplayMember 工作了。您不能将“Home”用作 ValueMember 作为其对象,您必须指向其属性之一(StreetName、GeoLocationX、GeoLocationY)。

    public partial class Form1 : Form
        {
    
            private List<UserDataModel> userData = new List<UserDataModel>();
    
            public Form1()
            {
                InitializeComponent();
                MyInit();
            }
    
            public void MyInit()
        {
            var mymodel = new UserDataModel("Derek", "999-999", new HomeDataModel("Sesame Street", 111, 222));
    
            var mymodel1 = new UserDataModel("John", "999-999", new HomeDataModel("Tin Can Alley", 333, 444));
    
            userData.Add(mymodel);
            userData.Add(mymodel1);
    
            BindingSource bs = new BindingSource();
            bs.DataSource = userData;
    
            comboBox1.DataSource = bs;
            comboBox1.DisplayMember = "Home.StreetName";
    
        }
    }
    
    internal sealed class UserDataModel
    {
        public string Name { get; set; }
        public string Phone { get; set; }
        public HomeDataModel Home { get; set; }
    
        public UserDataModel()
        {
    
        }
    
        public UserDataModel(string name, string phone, HomeDataModel home)
        {
            this.Name = name;
            this.Phone = phone;
            this.Home = home;
        }
    }
    
    internal sealed class HomeDataModel
    {
        public string StreetName { get; set; }
        public int GeoLocationX { get; set; }
        public int GeoLocationY { get; set; }
    
        public HomeDataModel()
        {
    
        }
    
        public HomeDataModel(string streetname, int x, int y)
        {
            this.StreetName = streetname;
            this.GeoLocationX = x;
            this.GeoLocationY = y;
    
        }
    }
    

    【讨论】:

    • 嗨 Derek,我也尝试过这个解决方案。它编译并......工作。但不是真的,因为我的 combobox1 只显示 1 个下拉字段:“芝麻街”。 comboBox1.Items.Count 也是 1。所以它真的不起作用。为什么 ?不知道...
    • 抱歉,我再看看这个。
    • 问题出在 HomeDataModel 上。您不能将它的三个属性包含在 UserDataModel 类中吗?我认为这将解决问题。
    • 感谢您的努力,德里克!显然,我可以将属性添加到 UserDataModel,但这损害了我的问题的基础:) 而且我还有许多其他需要 SubProperty 的 DisplayMember 的组合框。如果我将所有这些类合二为一,您会称其为“优秀的软件设计”吗? :)
    • 我对您应用程序的其余部分一无所知。 @马塞尔。这是一个有趣的问题。我会在今天的某个时候再看一遍。
    【解决方案4】:

    澄清一下:默认情况下,ComboBox 始终使用托管表单 BindingContext。我用该代码对其进行了测试:

                var bc = comboBox1.BindingContext;
            if (bc == this.BindingContext)
            {
                if (bc.Equals(this.BindingContext))
                {
                    MessageBox.Show("combobox always use same binding context as his hosting form");
                }
            }
    

    消息框已显示。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-29
      • 1970-01-01
      • 2011-07-17
      • 1970-01-01
      • 2011-08-06
      • 2020-01-31
      • 2012-12-30
      相关资源
      最近更新 更多