Apr 3, 2009

Nesting a Repeater inside of a GridView that is bound to an Array of Custom Objects

Wow, isn't that title a mouthful! But that's exactly the situation that presented itself to me at work this week. Since it too me way longer than I thought it should to figure out, I figured I'd put my effort in here, just in case it might be able to help someone else out someday (possibly even me).

Here's the results:
#NameEmail Addresses
1Ian CazabatIanCazabat@Example.com
Ian.B.Cazabat@Example.com
IanCaz@Example.com
2Malcolm ReynoldsCptnMal@Example.com
Serenity1@Example.com
3Jonas BlaneSnakeDr@Example.com
303rdLSG@Example.com


So, without any further delay here's the code:
ASPX:
<%@ Page Language="c-sharp" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Nested Sample</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="gvNestingSample" AutoGenerateColumns="False" runat="server" BackColor="White" BorderColor="#999999" BorderStyle="None" BorderWidth="1px" CellPadding="3" GridLines="Vertical">
<RowStyle VerticalAlign="Top" BackColor="#EEEEEE" ForeColor="Black" />
<Columns>
<asp:BoundField DataField="EmployeeId" HeaderText="#" />
<asp:BoundField DataField="EmployeeName" HeaderText="Name" />
<asp:TemplateField HeaderText="Email Addresses">
<ItemTemplate>
<asp:Repeater runat="server" ID="rptEmailAddrs" DataSource='<%# DataBinder.Eval( Container.DataItem, "EmailAddresses" ) %>'>
<ItemTemplate>
<a href="mailto:<%# Container.DataItem %>"><%# Container.DataItem %></a><br />
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<FooterStyle BackColor="#CCCCCC" ForeColor="Black" />
<SelectedRowStyle BackColor="#008A8C" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#999999" ForeColor="Black" HorizontalAlign="Center" />
<HeaderStyle BackColor="#000084" Font-Bold="True" ForeColor="White" />
<AlternatingRowStyle BackColor="#DCDCDC" />
</asp:GridView>
</div>
</form>
</body>
</html>


CodeBehind:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page {
protected void Page_Load( object sender, EventArgs e ) {
UserAccount[ ] aryUserAccounts = new UserAccount[ ] {
new UserAccount( 1, "Ian Cazabat", new string[] {"IanCazabat@Example.com", "Ian.B.Cazabat@Example.com", "IanCaz@Example.com"}),
new UserAccount( 2, "Malcolm Reynolds", new string[] {"CptnMal@Example.com", "Serenity1@Example.com"}),
new UserAccount( 3, "Jonas Blane", new string[] {"SnakeDr@Example.com", "303rdLSG@Example.com"})
};

gvNestingSample.DataSource = aryUserAccounts;
gvNestingSample.DataBind( );
}

public class UserAccount {
private long employeeid;
private string employeename;
private string[ ] emailaddresses;

public long EmployeeId {
get { return employeeid; }
set { employeeid = value; }
}
public string EmployeeName {
get { return employeename; }
set { employeename = value; }
}
public string[ ] EmailAddresses {
get { return emailaddresses; }
set { emailaddresses = value; }
}

public UserAccount( ) {
}

public UserAccount( long lEmployeeId, string strEmployeeName, string[] aryEmails ) {
this.employeeid = lEmployeeId;
this.employeename = strEmployeeName;
this.emailaddresses = aryEmails;
}
}
}

Okay, so there you have a working sample of how to create a GridView with a nested Repeater, that gets it's data from an Array of Custom Objects. Here's a couple points of interest:
  1. In order to bind on the data in the object, they must be created as "fields" using get/set.
  2. To access the array that's part of the object use:
    DataSource='<%# DataBinder.Eval( Container.DataItem, "{Array Property Name}" ) %>'
  3. To display the "data elements" from the array, you use:
    <%# Container.DataItem %>
  4. If the "data elements" in the array are custom objects, then you need to use the following:
    <%# DataBinder.Eval( Container.DataItem, "{Property of Custom Object from Array}" )%>
Okay, so that's about got it, hopefully I've helped someone out & I've likely kept myself from losing too much sleep over this issue again! So, go forth & create! ;)

2 comments:

Unknown said...

Thank you very much for this code! This is exactly what I am looking for.

On the "couple points of interest" section, what do I need to use in the #3 and #4?

Thanks Ian.

Anonymous said...

If the data is a string, just put:
<%# Container.DataItem %>

If it's an object, you need to put:
<%# DataBinder.Eval( Container.DataItem, "{Property of Custom Object from Array}" )%>

Example:
*lt;%# DataBinder.Eval( Container.DataItem, "Name" )%>

This will write out the property "Name" from the object that is the "Data Item".