3

Wondering the best way to populate a GridView with my object data.

I have to show a product list from an complex object Sale, whose structure is something like this:

class Sale {
    int id;
    List<SaleItem> saleItems;
}

class SaleItem {
    int id;
    int quantity;
    Product product;

    BillingAddress billingAddress;
    ShippingAddress shippingAddress;
}

class Product {
    int id;
    string name;
    List<BuyingConfiguration> buyingConfigurations;
}

class BuyingConfiguration {
    string name; // like size, color, material
    string value;
}

and my grid should look like this:

Sale Items
+---------+---+------------+------------+----------------+
| Name    | # | B. Address | S. Address | Configurations |
+---------+---+------------+------------+----------------+
| Ferrari | 2 | --         | --         | Color: red     |
|         |   |            |            | Engine: Xyz    |
+---------+---+------------+------------+----------------+
| Jax     | 1 | --         | --         | Color: blue    |
|         |   |            |            | Engine: Abc    |
+---------+---+------------+------------+----------------+

Should I implement an ObjectDataSource for my Sale object? Is there any better solution?


EDIT 2: Let me try to make myself clear: the problem is not how to the display configurations. My problem is that the Sale object is returned to my code from the persistence layer, thats the why I dont want the GridView to access Database directly. Instead, it needs to load all its data from my Sale object, how to achieve that?


EDIT:

The Grid markup as requested:

<asp:GridView runat="server" ID="GridProdutos" OnRowDataBound="GridProdutos_OnRowDataBound"
    AutoGenerateColumns="False">
    <Columns>
        <asp:BoundField HeaderText="Name" />
        <asp:BoundField HeaderText="#" />
        <asp:BoundField HeaderText="B. Address" />
        <asp:BoundField HeaderText="S. Address" />
        <asp:BoundField HeaderText="Configurations" />
    </Columns>
</asp:GridView>

Ugly solution so far, using OnRowDataBound (I want to avoid that!):

protected void GridProdutos_OnRowDataBound(object sender, GridViewRowEventArgs e) {
    if (e.Row.DataItem == null)
        return;

    SaleItem item = (SaleItem )e.Row.DataItem;

    e.Row.Cells[0].Text = item.product.name;
    e.Row.Cells[1].Text = item.quantity.ToString();

    StringBuilder sbConfigurations = new StringBuilder();

    foreach (BuyingConfiguration configurationItem in item.product.buyingConfigurations) {
        sbConfigurations.AppendFormat("{0}: {1}<br />", configurationItem.name, configurationItem.value);
    }
    e.Row.Cells[4].Text = sbConfigurations .ToString();
}
Yuri Ghensev
  • 2,507
  • 4
  • 28
  • 45
  • please show your page markup with the grid definition. – Davide Piras Oct 25 '11 at 16:39
  • I guess you could add a repeater control for displaying the config items. The data source of the repeater should be bound by by using the "Bind()" method of the given data source, which eliminates the RowDataBound stuff. Hope this Helps!! – Praveen Oct 25 '11 at 16:45
  • @Praveen But first I got to know how to load all the grid data directly from my `Sale` object, not from database (as I pointed in my second edit). – Yuri Ghensev Oct 25 '11 at 16:52

2 Answers2

3

I would suggest using the TemplateColumns with binding expressions. You can bind your GridView to the saleItems list, and implement getter methods to render each field given a SaleItem instance. For example, your Name column could be defined as follows:

            <asp:TemplateField>
                <ItemTemplate>
                    <%# ((SaleItem)Container.DataItem).product.Name %>
                </ItemTemplate>
            </asp:TemplateField>

The same thing could be done with a custom getter method to move the access details into the code-behind:

            <asp:TemplateField>
                <ItemTemplate>
                    <%# getSaleItemProductName((SaleItem)Container.DataItem) %>
                </ItemTemplate>
            </asp:TemplateField>

Don't forget to add an Import directive to be able to reference your types:

<%@ Import Namespace="YouNamespaceHere" %>
Alex Nazarov
  • 1,285
  • 1
  • 8
  • 6
1
  dataGridView1.DataSource = ToDataTable(SaleItems);

you can bind data directly to dataGridView if you can convert complex object list to Datatable as bellow

 private DataTable ToDataTable(List<Sale> SaleItems)
    {
        DataTable returnTable = new DataTable("Sale");
        returnTable.Columns.Add(new DataColumn("Name"));
        returnTable.Columns.Add(new DataColumn("#"));
        returnTable.Columns.Add(new DataColumn("B. Address"));
        returnTable.Columns.Add(new DataColumn("S. Address"));
        returnTable.Columns.Add(new DataColumn("Configurations"));

        foreach (Sale item in SaleItems)
        {
            returnTable.AcceptChanges();
            DataRow row = returnTable.NewRow();
            row[0] = item.product.name;
            row[1] = item.quantity.ToString();
            row[2] = item.billingAddress.ToString();
            row[3] = item.billingAddress.ToString();
            StringBuilder sbConfigurations = new StringBuilder();

            foreach (BuyingConfiguration configurationItem in item.product.buyingConfigurations) {
               sbConfigurations.AppendFormat("{0}: {1}<br />", configurationItem.name, configurationItem.value);
            }
            row[4] = sbConfigurations.ToString();

            returnTable.Rows.Add(row);
        }
        return returnTable;
    }
Damith
  • 62,401
  • 13
  • 102
  • 153
  • I like your approach to transform my object in a data table, but this way I keep my code pretty similar to the way it is already. I need a more "clean" solution. – Yuri Ghensev Oct 26 '11 at 13:26