I will be talking a bit of nested repeater and something you should be aware on the space indentation issue of an ASP.NET 2.0 Repeater control. So if you already know about how to achieve nested repeater, you can just look at Step 6 right at the bottom.
Parent Repeater
è Nested Repeater
Assuming you have 1 Applicant named Chua Wen Ching. Chua Wen Ching owns multiple programs which are Program A, Program B and Program C. Apparently each of this program has secondary owners. Example Program A is also owned by Eric, Kent and Sharon. Program B is only owned by Kent. Lastly Program C has no owner.
So you will see this:
Wen Ching
1. Program A
à Eric
à Kent
àSharon
2. Program B
à Kent
3. Program C
For this case, I can decide whether to place Wen Ching in the Parent repeater or outside the repeater. It is entirely up to you.
Example 1 – Outside of the repeater
<tr> <td colspan=”3”> <asp:Literal ID="ltrName" runat="server" /> </td> </tr> |
<tr> <td colspan=”3”> <asp:repeater /> </td> </tr> |
For this case, basically you can retrieve the name from the database and store into a literal control. Of course you can use any controls you want. Up to your creativity and needs.
You can do this as well if you want.
Example 2 – Inside the repeater
<tr> <td colspan=”3”> <asp:repeater …> <HeaderTemplate> <table …> <tr> <td> <%# DataBinder.Eval(Container.DataItem, "Name")%> </td> </tr> </table> </HeaderTemplate> </asp:repeater> </td> </tr> |
Take note, it is crucial that you place that Name inside the HeaderTemplate and not the ItemTemplate or else you will get duplicate names “Wen Ching” all over the place.
So this is how you expect to see in your web form.
Chua Wen Ching |
1 | : | Program A |
Also Owned By |
Eric |
Kent |
Sharon |
2 | : | Program B |
Also Owned By |
Kent |
3 | : | Program C |
Let’s look at the code below. This is a bit long, but bears with it. I will explain further right after the codes listing.
Listing1.cs
<asp:Repeater ID="rptParent" runat="server" OnItemDataBound="rptParent_ItemDataBound">
<HeaderTemplate>
<table id="tblParent" cellpadding="0" cellspacing="0" style="width: 100%">
</HeaderTemplate>
<ItemTemplate>
<tr>
<td colspan="3">
<table id="tblParent" cellpadding="0" cellspacing="0" style="width: 100%">
<tr>
<td style="width: 2%">
</td>
<td style="width: 20%">
</td>
<td style="width: 1%">
</td>
<td style="width: *">
</td>
</tr>
<tr>
<td style="vertical-align: top">
<strong>
<%# RecordNumber++ + "." %>
</strong>
</td>
<td>
<em>Program Name</em>
</td>
<td>
:
</td>
<td>
<%# DataBinder.Eval(Container.DataItem, "ProgramName")%>
</td>
</tr>
<tr>
<td>
</td>
<td>
<em>Program Date</em>
</td>
<td>
:
</td>
<td>
<%# DataBinder.Eval(Container.DataItem, "ProgramDate", "{0:dd-MMM-yyyy}")%>
</td>
</tr>
<tr>
<td colspan="4">
<br />
</td>
</tr>
<tr align="center">
<td colspan="4">
<asp:Repeater ID="rptChild" runat="server">
<HeaderTemplate>
<table id="tblChild" cellpadding="0" cellspacing="0" style="width: 90%">
<tr>
<th colspan="3">
Also owned by
</th>
</tr>
<tr>
<td colspan="3">
<br />
</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td style="width: 20%">
</td>
<td style="width: 1%">
</td>
<td style="width: *">
</td>
</tr>
<tr>
<td style="text-align: left">
<em>Extra Owner</em>
</td>
<td style="text-align: left">
:
</td>
<td style="text-align: left">
<%# DataBinder.Eval(Container.DataItem, "ExtraOwner")%>
</td>
</tr>
<tr>
<td colspan="3">
<br />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</td>
</tr>
<tr>
<td colspan="4">
<br />
</td>
</tr>
</table>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
Step 1
<tr>
<td style="vertical-align: top">
<strong>
<%# RecordNumber++ + "." %>
</strong>
</td>
<td>
<em>Program Name</em>
</td>
<td>
:
</td>
<td>
<%# DataBinder.Eval(Container.DataItem, "ProgramName")%>
</td>
</tr>
Basically you have this code inside your parent repeater ItemTemplate. It will auto increment depends on your data. Assuming you have 10 programs then you will have 1 – 10 numbers.
RecordNumber is a property in the codebehind. It is encourage that you assigned to 1 whenever you try to bind data to this repeater. Or else you will get a continuous counter value.
In order to bind the Program Name, you use the DataBinder.Eval. Take note, there are other ways to do it. This is just 1 way.
Remember the “ProgramName” is part of your data pulled from the database.
Example,
SELECT ProgramID, ProgramName FROM tbMIND
If you try to assign something here which is not part of the data source, you will get an error for sure.
Step 2
You can format your data easily like below.
<%# DataBinder.Eval(Container.DataItem, "ProgramDate", "{0:dd-MMM-yyyy}")%>
Well if you decide to do this within your Entity layer for formatting is still possible. Up to your coding choices.
Step 3
<asp:Repeater ID="rptChild" runat="server">
Okay you will add another repeater control within the ItemTemplate of the parent’s repeater. This is how nested works?
Looks easy right.
Step 4
Now, how do you populate data into this nested repeater?
First you need to assign an event “ItemDataBound” to your parent repeater. See the code below:
protected void rptParent_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
DataRow dr = ((DataRowView)e.Item.DataItem).Row;
Repeater childRpt = (Repeater)e.Item.FindControl("rptChild");
DataTable dTable = BizRule.PopulateChild(decimal.Parse(dr["ProgramID"].ToString()));
if (dTable.Rows.Count > 0)
{
childRpt.DataSource = dTable;
childRpt.DataBind();
}
}
}
There is no way you can access the Child Repeater directly from your page without using the FindControl method.
Repeater childRpt = (Repeater)e.Item.FindControl("rptChild");
Now the question is how am I able to get the row’s Program ID value?
You have to use DataRowView to cast the “e.Item.DataItem” in order to get the row and assigned to a DataRow like below.
DataRow dr = ((DataRowView)e.Item.DataItem).Row;
Then to get the value of the Program ID, do this
dr["ProgramID"].ToString()
Get this ProgramID and pass it to your method. As you see in my nested repeater, I am looking for other owners who have connections with this Program ID. Basically I have a static BizRule method called PopulateChild which accepts 1 parameter which is Program ID and returns a DataTable.
If you are using this DataTable way, it is best you check for dTable.Rows.Count > 0.
Then you get this DataTable and assign to the repeater DataSource and DataBind it. Just like you do for any other Data controls in ASP.NET 2.0.
Step 5
When you run this, you will get to see what you want.
However there is something that you will not expect to happen.
Below is a sample screen (using tables)
Chua Wen Ching |
1 | : | Program A |
Also Owned By |
Eric |
Kent |
Sharon |
2 | : | Program B |
Also Owned By |
Kent |
3 | : | Program C |
|
Take note, this only happens if you have more than 5 rows of data. You will not see if you have less than 5 rows. Give it a try.
That drives me crazy at first. As you know I have been using the html code for all my web development tables. Well it never went wrong before, not until using it in a repeater.
Step 6
There is a solution. If you read my other post, I use similar concept for the HTML table.
Add this
table-layout: fixed;
inside the tblParent’s style.
Example,
<asp:Repeater ID="rptParent" runat="server" OnItemDataBound="rptParent_ItemDataBound">
<HeaderTemplate>