Question

I am working with an object which has sub objects within (see example below). I am attempting to bind a List<rootClass> to the datagrid. When I bind the List<>, in the cell that contains the subObject, I see the following value ... "namespace.subObject" ... the string values display correctly.

Ideally I would like to see the “Description” property of the subObject in the datacell. How can I map the subObject.Description to show in the datacell?

public class subObject
{
   int id;
   string description;

   public string Description
   { get { return description; } }
}

public class rootClass
{
   string value1;
   subObject value2;
   string value3;

   public string Value1
   { get { return value1; } }

   public subObject Value2
   { get { return value2; } }

   public string Value3
   { get { return value3; } }
}
Was it helpful?

Solution

If I'm not mistaken, it shows the result of calling .ToString() on your subObject, so you can override that to return the contents of Description.

Have you tried just binding to Value1.Description? (I'm guessing it doesn't work).

I have a class that can be used instead of List when binding, that will handle this, it implements ITypedList, which allows a collection to provide more "properties" for its objects, including calculated properties.

The last version of the files I have are here:

https://gist.github.com/lassevk/64ecea836116882a5d59b0f235858044

To use:

List<rootClass> yourList = ...
TypedListWrapper<rootClass> bindableList = new TypedListWrapper<rootClass>(yourList);
bindableList.BindableProperties = "Value1;Value2.Description;Value3.Description";
gridView1.DataSource = bindableList;

Basically you bind to an instance of TypedList<T> instead of List<T>, and adjust the BindableProperties property. I have some changes in the work, including one that just builds up BindableProperties automatically as it goes, but it isn't in the trunk yet.

You can also add calculated properties, like this:

yourList.AddCalculatedProperty<Int32>("DescriptionLength",
    delegate(rootClass rc)
    {
        return rc.Value2.Description.Length;
    });

or with .NET 3.5:

yourList.AddCalculatedProperty<Int32>("DescriptionLength",
    rc => rc.Value2.Description.Length);

OTHER TIPS

Since you mention DataGridViewColumn (tags), I assume you mean winforms.

Accessing sub-properties is a pain; the currency-manager is bound to the list, so you only have access to immediate properties by default; however, you can get past this if you absolutely need by using a custom type descriptor. You would need to use a different token too, like "Foo_Bar" instead of "Foo.Bar". However, this is a major amount of work that requires knowledge of PropertyDescriptor, ICustomTypeDescriptor and probably TypeDescriptionProvider, and almost certainly isn't worth it,

The simplest fix is to expose the property as a shim / pass-thru:

public string Value2Description {
    get {return Value2.Description;} // maybe a null check too
}

Then bind to "Value2Description" etc.

I'm not sure whether you are using ASP.NET, but if yes, then you can use a template column and the Eval() method to display values of nested objects. E.g. to display the Description property of the subObject:

<asp:GridView ID="grid" runat="server" AutoGenerateColumns="true">
  <Columns>
    <asp:TemplateField>
      <ItemTemplate>
        <asp:Literal Text='<%# Eval("Value2.Description") %>' runat="server" />
      </ItemTemplate>
    </asp:TemplateField>
  </Columns>
</asp:GridView>

Not sure if it's something like this you are after...

You could write a method like:

protected string getSubObject(object o)
{
    string result = string.empty;

    try
    {
        result = ((subObject)o).Description;
    }
    catch
    { /*Do something here to handle/log your exception*/ } 

    return result;
}

Then bind the object something like this:

<asp:Literal Text='<%# getSubObject(Eval("Value2")) %>' runat="server" />
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top