3

I am trying to bind a ListBox Control in C# Winforms in .NET 4.5 to a list of objects that have a nested property that I wish to use for a DisplayMember. It sort of works except that when I set the DisplayMember to the nested property the listbox only shows one item even though there are two items in the list that it is bound to. If I comment out the code for setting the DisplayMember the listBox shows two items. Is this a bug in the framework? I would like to avoid adding another property or overriding ToString() if I can since I am implementing MVP and would like to keep my view logic isolated to my view. Here is some example code below.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        var bindingSource = new BindingSource();
        var listOfMyItems = new BindingList<MyItem>
        { 
          new MyItem { Number = 1, NestedItem = new NestedItem { Name = "name1", Note = "note1" } },
          new MyItem { Number = 2, NestedItem = new NestedItem { Name = "name2", Note = "note2" } },
        };
        bindingSource.DataSource = listOfMyItems;
        listBox1.DataSource      = bindingSource;
        //comment out the line below and the listBox1 will show 2 items
        listBox1.DisplayMember   = "NestedItem.Name";
    }
}
public class NestedItem
{
    public string Name { get; set; }
    public string Note { get; set; }
}
public class MyItem
{
    public NestedItem NestedItem { get; set; }
    public int Number { get; set; }
}
jeffreyk
  • 123
  • 1
  • 8

1 Answers1

3

It seems that setting DisplayMember to "NestedItem.Name" only displaying NestedItem.Name property of SelectedItem -I tested this, if SelectedItem changed, the Name displayed also changed accordingly-. The easiest work around is to add another property for DisplayMember :

public class MyItem
{
    public NestedItem NestedItem { get; set; }
    public int Number { get; set; }
    public String NestedItemName { get { return NestedItem.Name; } }
}

Then set the DisplayMember :

listBox1.DisplayMember   = "NestedItemName";

Not elegant, but still easier than using property descriptior as suggested here or here.

UPDATE :

Following is a quick test I did. Add a button to toggle listBox1's DisplayMember. Onclick event handler :

listBox1.DisplayMember = (listBox1.DisplayMember == "Number") ? "NestedItem.Name" : "Number";

when DisplayMember set to "Number" you can choose any item in list -not necessarily the first item-, then click the button again. You'll see that SelectedItem's NestedItem.Name displayed.

Community
  • 1
  • 1
har07
  • 88,338
  • 12
  • 84
  • 137
  • How did you test the changing of the selectedItem? Cause when I put in code listBox1.SelectedIndex = 1; I get an argument out of range exception. I really wanted to avoid trying to have another property that is used just for display as I am trying to implement MVP and would like to keep view logic isolated to my view. But if there is no actual solution then I may have to go with that workaround. – jeffreyk Dec 28 '13 at 19:59
  • Check my update to see how I did the test. As suggested in the first link, you can separate for-display-only properties in another partial class so it didn't mixed up with original model properties -*at least, physically separated despite logically it still single class*-. – har07 Dec 28 '13 at 22:24
  • Perfect, I added a Get-Only Property: public string DisplayMember { get { return ToString(); } } to get my Public Method: public override string ToString() and now the listbox works just fine. – Ola Ström Mar 31 '20 at 21:16