Introduction
This article is a small demo project that uses nested Repeater
s to display a variable number of DataTable
objects with the same schema.
Using the code
Before I continue, I realize that the following solution is not exactly the most elegant, but it works, and criticisms are most welcome.
We have two Repeater
controls. The inner Repeater
control is placed within a User Control, while the outer Repeater
is contained with the APSX page, with its <ItemTemplate>
being the User Control.
Before we go into the details of the controls, first, let’s introduce the small customDataItem.cs class in the App_Code folder. For some reason, when I bind a DataSet
, the Repeater
s do not render all of the tables as expected, but actually repeats the last DataTable
in the set several times. So, the alternative approach was to encapsulate each of the DataTable
object within a new object. So, I created a class called CustomDataItem
.
public class CustomDataItem
{
private DataTable _Data;
public DataTable Data { get { return _Data; } set { _Data = value; } }
public CustomDataItem(DataTable data)
{
_Data = data;
}
}
As you can see, it’s a very simple class that encapsulates a DataTable
object passed as a parameter to the constructor. That’s it, basically.
Next, we have the User Control (.ascx) code that contains the inner Repeater
. It’s fairly simple and self-explanatory. You will notice that I have a Literal
control as a header. The Literal
text will be set to the table name when data bound.
<h2><span><asp:Literal runat="server" ID="ltrTableName"/></span></h2>
<asp:Repeater ID="innerRep" runat="server">
<HeaderTemplate>
<table cellpadding="2" cellspacing="5" border="true">
<thead>
<tr>
<th><b>Name</b></th>
<th><b>Address</b></th>
<th><b>PostCode</b></th>
</tr>
</thead>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%# DataBinder.Eval(Container.DataItem,"Name") %></td>
<td><%# DataBinder.Eval(Container.DataItem,"Address") %></td>
<td><%# DataBinder.Eval(Container.DataItem,"PostCode") %></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
Now, for the code-behind of the user control:
public partial class InnerRepeaterUserControl : System.Web.UI.UserControl
{
private CustomDataItem _DataItem;
public CustomDataItem DataItem { get { return _DataItem; }
set { _DataItem = value; } }
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
BindData();
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
}
private void BindData()
{
try
{
binnerRep.DataSource = _DataItem.Data;
innerRep.DataBind();
ltrTableName.Text = _DataItem.Data.TableName;
}
catch { }
}
The BindData()
method binds the DataTable
contained within the CustomDataItem
object and the Literal
text to the table name. The CustomDataItem
is passed in the innerRepeater_DataBound()
event fired on the main ASPX page. We will go into details a little later on.
The ASPX code on the web page is simple enough. Here, all we do is register the user control and add the outer Repeater
, as well as set the reference to the outer Repeater
's ItemDataBound
method.
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Src="~/InnerRepeaterUserControl.ascx"
TagPrefix="uc" TagName="InnerRep" %>
<!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>Repeater Demo</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Repeater runat="server" ID="outerRepeater"
onItemDataBound="outerRepeater_ItemDataBound">
<ItemTemplate>
<uc:InnerRep runat="server" ID="tblInnerRep" />
</ItemTemplate>
</asp:Repeater>
</div>
</form>
</body>
</html>
The C# code-behind of the web page is where most of the work is done. In this example, I created three simple data tables in the code in createDataTables()
, and added them to a generic list of CustomDataItem
objects.
BindData()
simply calls the method and binds the list to the outer Repeater
.
Finally, in outerRepeater_ItemDataBound
, we find the inner Repeater
control, cast the e.DataItem
of the outer Repeater
to a CustomDataItem
, and set this as the inner Repeater
's DataItem
.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
base.OnInit(e);
BindData();
}
}
private void BindData()
{
List<CustomDataItem> dataItems = createDataTables();
outerRepeater.DataSource = dataItems;
outerRepeater.DataBind();
}
private List<CustomDataItem> createDataTables()
{
List<CustomDataItem> dataItems = new List<CustomDataItem>(3);
dataItems.Add(new CustomDataItem(tbl1));
dataItems.Add(new CustomDataItem(tbl2));
dataItems.Add(new CustomDataItem(tbl3));
return dataItems;
}
protected void outerRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.DataItem is CustomDataItem)
{
CustomDataItem dataItem = e.Item.DataItem as CustomDataItem;
InnerRepeaterUserControl ctrl =
e.Item.FindControl("tblInnerRep") as InnerRepeaterUserControl;
if (ctrl != null)
ctrl.DataItem = dataItem;
}
}
Points of interest
None.
History
No changes.