Hierarchies with Nested Repeaters in ASP.NET
Thursday, July 6th, 2006In most every project I have ever worked on there is some type of hierarchy to the data and ultimately I need to represent this data in some hierarchical fashion to the user. Nested repeaters work very well in these situations and are quite easy to implement.
I am a big proponent of the repeater control and use it almost exclusively for representing repeating data structures. I find that the GridView control is overly-complicated and too tightly integrated with the aspx page for my tastes. I do use the DataList on occasion when I need to represent horizontal-repeating data.
For purposes of a demonstration let us say that we need to create a report that represents an order for products from a hypothetical customer. An order has a hierarchy consisting of an Order object which contains one or many OrderItems. Here is the Repeater section of our report:
OnItemDataBound=”Order_ItemDataBound”>
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, “OrderID”) %><br />
<asp:Repeater ID=”OrderItems” runat=”server”>
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, “ItemID”) %><br />
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
This overly-simplified example report contains 2 repeaters: Order and OrderItems. We can just place the nested repeater (OrderItems) right in the ItemTemplate section of our parent repeater (Order).
On the Page Load event we bind the Order repeater as we normally would.
{
Order.DataSource = GetOrder(Request.QueryString[”OrderID”].ToString);
Order.DataBind();
}
The nested repeater is bound on the ItemDataBound event of the Order repeater and we need to create a handler for the ItemDataBound event on the Order repeater as follows:
{
RepeaterItem item = e.Item;
if ((item.ItemType == ListItemType.Item) ||
(item.ItemType == ListItemType.AlternatingItem))
{
Repeater rptr2 = (Repeater)item.FindControl(”OrderItems”);
//Get the ID for the current row.
DataRowView row = (DataRowView)e.Item.DataItem;
string orderID = row[”OrderID”].ToString();
//Get the nested data for this item.
DataSet dsOrderDetails = GetOrderDetails(orderID);
rptr2.DataSource = dsOrderDetails;
rptr2.DataBind();
}
}
Be careful with large sets of data as this can become very chatty due to the need to call the database on each ItemDataBound event. In a situation like this example I would build a custom Order class to represent my objects using a Generic List instead of fussing with clumsy DataReaders or DataSets.