4

I'm trying to set the DisplayMember Property of my ListBox in a windows forms project to a property of a nested class inside a Generic List I am binding to.

Here's a simple example:

 public class Security
{
    public int SecurityId { get; set;}
    public SecurityInfo Info { get; set;}
}
public class SecurityInfo
{        
    public string Description { get; set;}
}
//........//
public void DoIt()
{
    List<Security> securities = new List<Security>();
    //add securities to list
    lstSecurities.DataSource = securities;
    lstSecurities.DisplayMember = "Info.Description";
}

Is this possible with a simple ListBox or will I have to create a subclassed ListBox to handle this?

edit:

I am trying not to modify these classes as they are being generated via a WSDL Document.

ncyankee
  • 1,248
  • 3
  • 19
  • 27

6 Answers6

5

No, most winforms bindings do not support child properties like this.

You can do it directly with custom type-descriptors, but that is a lot of work and not worth it.

Check the generated code; it should (with any recent version of the tools) be a partial class; that means you can add extra members in a second class file, so you don't break the wsdl-generated code - i.e.

namespace MyWsdlNamespace {
    partial class MyClass {
        public string InfoDescription {
            get { return Info.Description; }
            // and a set if you want
        }
    }
}

You should now be able to bind to "InfoDescription" fairly easily.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • "No, most winforms bindings do not support child properties like this." Has this changed since this post was made? I know that, at least when binding to controls, it is possible to bind to child properties as follows: `txtDesc.DataBindings.Add("Text", new BindingSource(security, null), "Info.Description");` – Dan Bechard Jul 25 '13 at 12:49
  • Any links on how to do it with custom type-descriptors? I'll bite the bullet and decide whether it's worth the effort. – Matt Arnold Jun 23 '22 at 17:16
2

You could add a new property that maps to Info.Description.

Something like this:

public string InfoDescription
{
  get { return Info.Description; }
  set { Info.Description = value; }
}

This will work. But I thought your example should work as well

Rune Grimstad
  • 35,612
  • 10
  • 61
  • 76
1

I know several answers that might work for you have already been posted, and this question is 3 years old, but I wanted to add another option because I ran into this issue when data-binding with objects in the Entity Framework.

I was binding to a ListBox, but wanted to display text from a child object. All I did was handle the ListBox.Format event, and change the ListControlConvertEventArgs.Value. I could get my child object because the DisplayMember I chose for the ListBox is the parent object itself, and it could be accessed in the event by ListControlConvertEventArgs.ListItem.

For example, the ListBox is databound to a binding source with a list of objA's. objA has a property for a child object, objB. The DisplayMember for the ListBox (set at design time) is objB. But, since the ToString() method doesn't return what I want for objB, I handle the Format event of the ListBox and set e.Value (with e being the ListControlConvertEventArgs) to the object I'm looking for:

CType(e.ListItem, objA).objB.DisplayText
Scott
  • 21,211
  • 8
  • 65
  • 72
jgreg311
  • 71
  • 2
  • While the accepted answer is good, this is much more better. For those who are confused about what he is saying... Here is a code example for what you place in the `ListBox.Format event method`: `e.Value = ((Loan)e.ListItem).Resource.Title;` Loan is my custom class, I assigned a `BindingList` to my `ListBox.DataSource`. – Tyler Nov 08 '17 at 17:53
0

Worth to see is

http://www.mail-archive.com/advanced-dotnet@discuss.develop.com/msg06383.html

Maciej
  • 10,423
  • 17
  • 64
  • 97
0

Yes, binding to nested properties can be done through a BindingSource. The comment of Dan at Jan 25 has shown how this can be done for "simple binding" ie binding to a single obejct's nested properties. For "complex binding" to collections, this is how it should be:

public void DoIt()
{
    List<Security> securities = new List<Security>();

    var securitiesBindingSource = new BindingSource();
    securitiesBindingSource.DataSource = securities;

    //add securities to list
    lstSecurities.DataSource = securitiesBindingSource;
    lstSecurities.DisplayMember = "Info.Description";
}

Subtle WARNING: The objects of the collection should be descendants of the same type, thus the Info should be of the same type. Interface covariance will not trick it into working when the Info property is dependent on a type parameter even if it is covariant, as this will make Info a covariant but different type, for example, when Info is of type Information<out P>.

grammophone
  • 601
  • 6
  • 8
0

Just override SecurityInfo ToString method to return Description and do:

lstSecurities.DisplayMember = "Info";

If you can't modify the classes, the best option would be to use a ViewModel. A class that takes a Security and exposes the properties you want to view.

gcores
  • 12,376
  • 2
  • 49
  • 45