Binding a object with a sub objects as properties to a datagrid
Asked Answered
K

4

8

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; } }
}
Katinka answered 2/1, 2009 at 15:44 Comment(1)
This is one of the shortcomings of DGV that I absolutely hate and why I almost always bind to an IEnumerable of an anonymous type.Feodora
E
8

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);
Edmundedmunda answered 2/1, 2009 at 15:49 Comment(6)
Just for info, ITypedList is mainly 1.1; in 2.0 you can use TypeDescriptionProvider on the underlying type (i.e. the T in the List<T>) to do the same.Altricial
Glad to see I'm not the only fool to have explored the depths of TypeDescriptor, though ;-pAltricial
I will look into TypeDescriptionProvider then :)Edmundedmunda
You can get a quick intro if you look at the HyperDescriptor code (just search). Once you've got as far as GetProperties() it should be familiar ;-pAltricial
Lasse, I know this question is old but do you still keep the source somewhere available online? The above url returns a 500 error and I am very interested in the TypedList<T> code?Leialeibman
The code is unfortunately long gone. The answer as such holds little value. I'll edit in a note about this. Apologies for the inconvenience. I think maybe there is a copy of the source code in a work project, I'll check that after the vacation, I'll make a note on my todo list to do that and come back with a definitive update.Edmundedmunda
A
9

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.

Altricial answered 3/1, 2009 at 12:10 Comment(0)
E
8

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);
Edmundedmunda answered 2/1, 2009 at 15:49 Comment(6)
Just for info, ITypedList is mainly 1.1; in 2.0 you can use TypeDescriptionProvider on the underlying type (i.e. the T in the List<T>) to do the same.Altricial
Glad to see I'm not the only fool to have explored the depths of TypeDescriptor, though ;-pAltricial
I will look into TypeDescriptionProvider then :)Edmundedmunda
You can get a quick intro if you look at the HyperDescriptor code (just search). Once you've got as far as GetProperties() it should be familiar ;-pAltricial
Lasse, I know this question is old but do you still keep the source somewhere available online? The above url returns a 500 error and I am very interested in the TypedList<T> code?Leialeibman
The code is unfortunately long gone. The answer as such holds little value. I'll edit in a note about this. Apologies for the inconvenience. I think maybe there is a copy of the source code in a work project, I'll check that after the vacation, I'll make a note on my todo list to do that and come back with a definitive update.Edmundedmunda
P
3

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>
Parenteau answered 2/1, 2009 at 17:27 Comment(0)
F
1

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" />
Forborne answered 24/8, 2011 at 14:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.