Click here to Skip to main content
Click here to Skip to main content

A quick guide to using nested repeaters in ASP.NET

By , 19 Feb 2004
 

Introduction

I've never really been much of a web-developer and never thought I'd find web-development all that interesting. But I must say I've been quite fascinated by what little ASP.NET I've done up till now, which is not a lot to be honest. One control I found particularly useful was the Repeater control, but I struggled a little when I tried to implement nested repeaters using an XML file as the data store. Eventually, the solution turned out to be embarrassingly easy, and I thought I'd write a little article for other first-timers who might encounter the same annoying situation I did.

Note to readers

I assume that you already know how to use a Repeater control. This article only shows you how to implement nested repeaters and will not attempt to explain repeaters in general.

Example

I am going to demonstrate a simple ASP.NET web application that will list out a Cricket World XI using an XML file as the input-data. Eventually, modification of the team simply involves a change in the XML file with no changes required either in the aspx pages or in the code-behind files.

My XML file

Essentially I have four categories - and each category has one or more players.

Implementing nested repeaters

I am going to list the categories first and inside each category I will list the players under that category. Lets first add the outter repeater that will list the categories.

We now add the inner repeater to the <ItemTemplate> tag of the outter repeater.

Writing the code-behind code

Alright, I know that "code-behind code" sounds weird, but I couldn't think of anything better sounding and if anyone has any better ideas, please drop me a line. Anyway we setup the first repeater in the Page_Load event handler as usual.

private void Page_Load(object sender, System.EventArgs e)
{
    DataSet ds = new DataSet();
    ds.ReadXml(MapPath("./XMLFile1.xml"));
    CategoryRepeater.DataSource = ds;
    CategoryRepeater.DataBind();
}

For setting up the outter repeater, we handle the ItemDataBound event of the Repeater class which is raised when an item is data-bound but before it is rendered on the page. We now get a reference to the PlayerRepeater control using RepeaterItem.FindControl and set its data source using CreateChildView and the automatic relation that's made for us - category_cricketer. By the way I was quite impressed by that, I never expected automatic relations to be created based on the XML. Pretty cool I think!

private void CategoryRepeater_ItemDataBound(object sender, 
    System.Web.UI.WebControls.RepeaterItemEventArgs e)
{
    RepeaterItem item = e.Item;
    if( (item.ItemType == ListItemType.Item) ||
        (item.ItemType == ListItemType.AlternatingItem) )
    {
        PlayerRepeater = (Repeater) item.FindControl("PlayerRepeater");
        DataRowView drv = (DataRowView)item.DataItem;
        PlayerRepeater.DataSource = drv.CreateChildView("category_cricketer");
        PlayerRepeater.DataBind();
    }
}

That's all.

The output

I got the below output when I viewed the web-form in my browser.

Conclusion

Feedback and criticism is welcome as usual. I'd also like to thank Aravind Corera (Chennai based C# MVP) who gave me the right URLs to solve this problem when I was tearing my hair out in frustration.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Nish Sivakumar
United States United States
Member
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
 
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site - www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff - blog.voidnish.com.
 
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy Summer Love and Some more Cricket as well as a programming book – Extending MFC applications with the .NET Framework.
 
Nish's latest book C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
 
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionGood ArticlememberAlireza_136219 Mar '13 - 22:45 
Thanks
QuestionPossible to include paging?memberTyng20 Jan '13 - 14:24 
Hi Nish,
 
Thank you for the article. However, is there possible to include paging function if the repeater list is too long?
 
What is your recommendation? I have 3 repeaters means 3 hierarchies. I am stuck in the paging of repeater.
 
Best regards,
Tyng
QuestionA better Tutorial heremembertim cadieux26 Jul '12 - 6:50 
See here Thorough Tutorial on using Nested Repeaters at http://everymanprogrammer.com/index.php/nested-repeaters-do-it-clean-and-simple-a-beginners-tutorial-part-1/
GeneralBetter Way!!memberimsathy20 Jan '08 - 23:40 
The article is really good.. but I feel providing the datasource directly is better than getting the source for the nested repeaters in ItemDataBound event.
 
<asp:Repeater runat="server" ID="myrep">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><b>
<%#((System.Xml.XmlElement)Container.DataItem).SelectSingleNode("@type").InnerText%>
<br />
<asp:Repeater runat="server" ID="cric" DataSource='<%#((System.Xml.XmlElement)Container.DataItem).SelectNodes("cricketer")%>'>
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<%#((System.Xml.XmlElement)Container.DataItem).InnerText%>
</li>
</ItemTemplate>
<FooterTemplate>
</ul></FooterTemplate>
</asp:Repeater></li>
</b>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>

 
Smile | :)
 
Sathy

GeneralRe: Better Way!!memberMaciej Pilichowski5 Mar '11 - 23:31 
Thank you very much! Even without any explanation your code is extremely clear and this tells a lot which approach is better.
GeneralRe: Better Way!!memberMarco Bertschi4 Mar '13 - 7:36 
Ï understand your idea. But IMO this code won't work anymore as soon as you use a database behind it.
Correct me if I am wrong.
cheers
Marco Bertschi

Software Developer & Founder SMGT Web-Portal
CP Profile | My Articles | Twitter | Facebook | SMGT Web-Portal

Freedom, son, is a dirty shirt

- The Boss

QuestionI have a problem when use printed review to check nested repeater aspx pagesmemberYingHsuan25 Nov '07 - 23:02 
Thanks a lot for the thorough explained article( especially thank the generous author), I do a great aspx page with nested repeater.
But when I try to print it, it came a problem: Can't print with a printer!
After check all setting, I found if we viewed this page with printed review, the single page on the screen become an infinte one.
 
I checked each page stamps again and again, search any possible keyword on the net but I am still totally at a loss what to do.
 
Could any one who mastered take me out from this swamp?
Any opinion will be appreciated!
 
Thanks for your help and patient.

 
sample page link as this
[^]
 
sorry for ask twice. (the other one at http://www.codeproject.com/aspnet/Server_Nested_Repeaters.asp[^] I really need to know how to solve it, thanks.
yhshih
AnswerRe: I have a problem when use printed review to check nested repeater aspx pagesmemberYingHsuan27 Nov '07 - 4:47 
I found the answer by a friend's help,
The "write-mode:tb-rl" in font tag makes infinte pagination during printer review, move it to
solved it.
Thaks anyway.Big Grin | :-D
GeneralWith tableAdapter instead of xml filememberwerge14 Sep '07 - 10:14 
Only the code behind needs to be changed:
 
protected void Page_Load(object sender, System.EventArgs e)
{
LinksTableAdapters.CategoryTableAdapter Cat = new LinksTableAdapters.CategoryTableAdapter();
CategoryRepeater.DataSource = Cat.GetData();
CategoryRepeater.DataBind();
}
 
private void CategoryRepeater_ItemDataBound(object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
if ((item.ItemType == ListItemType.Item) ||
(item.ItemType == ListItemType.AlternatingItem))
{
PlayerRepeater = (Repeater)item.FindControl("PlayerRepeater");
LinksTableAdapters.LinksTableAdapter myItems = new LinksTableAdapters.LinksTableAdapter();
DataRowView drv = (DataRowView)item.DataItem;
PlayerRepeater.DataSource = myItems.GetLinksByParameter(int.Parse(drv.Row.ItemArray.GetValue(0).ToString()));
PlayerRepeater.DataBind();
}
}

I have 2 different tableAdapter SQL Select calls, 1 for getting the list of Categories, and 1 for getting the Items belonging to the specific category, I do this my adding a paramenter to the myItems.GetLinksByParameter() call.
 
I hope this is usefull

 
Werge
GeneralNested Repeatersmemberremya3003@yahoo.com22 Jun '06 - 17:36 
Nish,Could u just explain me how i could bring in a Button click event in the chile repeater...
GeneralProblem in Convertingmemberkevinbhavasar3 Apr '06 - 1:18 
Hello Nish,
This is very good solution which i want. But i am getting problem in converting an object from DataItem to DataRowView as i want this code in VB.Net.
i write this,
Dim drv As DataRowView = CType(rptrItem.DataItem, DataRowView)
But it gives me error so tell me the solution.
 

waiting for solution
 
Kevin C. Bhavsar
MCA-SPU
Generali want to bind to a table not xml file with teh same issue title and users under tilememberGiiiO8 Nov '05 - 23:28 
how can i do it using a database table instead of xml file. i used datatable to get teh data from the databse into the table
 
gIo
Generali want to bind to a table not xml file with teh same issue title and users under tilememberGiiiO8 Nov '05 - 23:28 
how can i do it using a datable
 
gIo
GeneralRequires at least two Child Nodesmemberjavafreddie6 Apr '05 - 15:55 
I couldn't figure out why this worked when I tried your example, but wouldn't work for me when I tried it on my own problem.   Finally, after lots of frustration, I discovered that unless the child element (cricketer in your case) has at least two entries (can be empty) in at least one of the parent element instances, no relationship is set up and you get an error.   To me, this looks like a bug, but I might just be missing something obvious.  
 
System.ArgumentException: The relation is not parented to the table to which this DataView points.
 
Source Error:
 

Line 58:                     PlayerRepeater = (Repeater) item.FindControl("PlayerRepeater");
Line 59:                     DataRowView drv = (DataRowView)item.DataItem;
Line 60:                     PlayerRepeater.DataSource = drv.CreateChildView("category_cricketer");
Line 61:                     PlayerRepeater.DataBind();
Line 62:                }

when xml looks like
 
<?xml version="1.0" encoding="utf-8" ?>
<cricketers>
     <category type="Bowlers">
           <cow>Betsy</cow>
          <cricketera>Wasim Akram</cricketera>
          <cricketera>Michael Holding</cricketera>
          <cricketera>Shane Warne</cricketera>
          <cricketera>Muthaiah Muralidaran</cricketera>
     </category>
     <category type="Batsmen">
           <cow>Moo Moo</cow>
          <cricketer>Geoff Boycott</cricketer>
          <cricketera>Sunny Gavaskar</cricketera>
          <cricketera>Sachin Tendulkar</cricketera>
          <cricketera>Vivian Richards</cricketera>
     </category>    
     <category type="Allrounders">
           <cow>Yack</cow>
          <cricketera>Kapil Dev</cricketera>
          <cricketera>Ian Botham</cricketera>
     </category>    
     <category type="WicketKeeper">
           <cow>John</cow>
          <cricketera>Adam Gilchrist</cricketera>         
     </category>    
</cricketers>
 
Notice that the cricketer tag exists only once within only one category.   This causes a failure as shown above.   By removing the suffixing a on one other tag in that category, giving you two cricketer tags, it works fine.
 
Also,   I find it kind of limiting that you can't wrap a listbox control inside a repeater because the parser complains that a listitem must be the only item inside a listbox control.   That kind of sucks, because it keeps you from building a list inside a nested repeater.Mad | :mad:
 

 
Javafreddie
GeneralRe: Requires at least two Child Nodesmember7.e.Q3 Jul '07 - 9:06 
Can somebody please comment this issue? I run into the same problem with all of my own data relations.
 
Is it a bug? Can it be fixed?
GeneralThis code cant be completesussAnonymous31 Mar '05 - 3:33 
There are no event fired when databinding occurs. This code doesnt create any details at all...
GeneralRe: This code cant be completememberJeff Lehmer30 Sep '06 - 9:45 
okay, i know this is an old post but i'll respond anywayz. some new person may want to see what a solution to this problem is. nishant wrote a good article but he didn't provide _everything_. this solution may not be what he did, either. WTF | :WTF:
 
you need to remember to put the event in the repeater tag:
 
<asp:Repeater id="CategoryRepeater" OnItemDataBound="CategoryRepeater_ItemDataBound" Runat="server">
 
i'm assuming you've already already registered for the event in your code-behind:
 
CategoryRepeater.ItemDataBound += new RepeaterItemEventHandler(CategoryRepeater_ItemDataBound);
 
with the "public" event handler.
 
Jeff

GeneralRe: This code cant be completememberAlex Stephens7 Jan '13 - 2:32 
Here's a really simple example of how to nest repeaters
http://www.thewebdevelopers.com/asp-repeater-in-repeater/[^]
GeneralNested User ControlsmemberMiszou14 Feb '05 - 14:05 
First of all, great article, just what I needed.
 
But.... how can I put a user control into the repeater? I have a simple user control that is nothing more than a combo box with a list of items and id's from a database. (Imagine a list of Countries with CountryID)
 
When I put the control in the web-page, it works perfectly, but as soon as I nest it inside a repeater control, I get an error: The IListSource does not contain any data sources
 
As far as I can see, the control shouldn't need any special processing in the ItemDataBound event, as it is all encapsulated inside the control itself...

 
[edit]
Never mind, it was something silly I was doing! Blush | :O
[/edit]
Generalneed more explanation.memberpurplerain22 Sep '04 - 10:20 
what do the "type" and "cricketer_text" stand for here??
suppose i have a file which has nodes like name and url...how would i bind the same?
can anyone help me?
thanks.
GeneralAn alternativememberIan Darling21 Feb '04 - 1:30 
I've you've got a DataSet with two DataTables and appropriate DataRelations set up, you can DataBind the DataSource in the ASP.NET code directly using the GetChildRows function.
 
I had to write several ASP.NET reports sometime ago with multiple levels of nesting (up to 9!), and found that the fastest and easiest way to do it was to have a hefty DataSet and DataTables that covered the levels of nesting.
 
For your example, I would have had two DataTables:
Table 1 ("PlayerTypes"):
PlayerType
----------
Bowlers
Batsmen
Allrounders
WicketKeeper
Table 2 ("Players"):
PlayerType   Player
----------   ------------
Bowlers      Wasim Akram
Batsmen      Geoff Boycott
Batsmen      Sunny Gavaskar
Bowlers      Michale Holding
etc.....
Set up a DataRelation between them (like myDataSet.Relations.Add("PlayerTypesRel", myDataSet.Tables["PlayerTypes"].Column["PlayerType"], myDataSet.Tables["Players"].Column["PlayerType"])
 
Then the nexted repeaters look like (simplified from HTML lists to bold playertypes and italic players):
<asp:repeater id="PlayerTypesRepeater" runat="server">
<itemtemplate>
    <b><%# DataBinder.Eval(Container.DataItem, "PlayerType") %></b>
    <asp:repeater id="PlayersRepeater" runat="server"
            datasource='<%# Container.DataItem.Row.GetChildRows("PlayerTypesRel") %>'>
    <itemtemplate>
        <i><%# DataBinder.Eval(Container.DataItem, "Player") %></i>
    </itemtemplate>
    </asp:repeater>
</itemtemplate>
</asp:repeater>
(also note that after the first level of nesting, the RowView changes to a Row too, so you use DataItem.GetChildRows instead of DataItem.Row.GetChildRows)
 
This is from memory and untested, but it's essentailly how I did it, and it worked great.
 
Hope that is useful Smile | :)
 

Ian Darling
"One of the few systems...which has had “no deaths” in the reliability requirements." - Michael Platt
GeneralRe: An alternativesussScott Galloway21 Feb '04 - 1:39 
Very nice...(well apart from DataBinder.Eval Smile | :) )...I still generally prefer to use Codebehind to provide the datasource for the nested control...but this is still a cool method...
GeneralRe: An alternativememberIan Darling21 Feb '04 - 1:42 
Scott Galloway wrote:
well apart from DataBinder.Eval
 
I was doing it from memory. I think I actually used String.Format(Container.DataItem), "format") where I was dealing with non string objects, just dumped them out when I was, and I didn't read your post about it until afterwards, which reminded me D'Oh! | :doh: Smile | :)
 

Ian Darling
"One of the few systems...which has had “no deaths” in the reliability requirements." - Michael Platt
GeneralA couple of small points...this is not the most efficient methodmemberScott Galloway21 Feb '04 - 0:46 
I was also a big proponent of the OnItemDataBound method until recently, now I've moved to using the 'Member Method' approach, partly for the code being a bit 'clenaer' and partly for better performance (less casting, doesn't use events etc..) I posted about this here: http://www.mostlylucid.co.uk/posts/837.aspx .
Also, if you don't need to use DataBinder.Eval, there's really very little reason to use it - and it can have an impact on performance since it uses reflection to determine the datatype of the DataItem - mostly unnecessary since you will already know this in most cases. You can gain around 20% in raw performance by specifying the datatype of the DataItem, e.g., ((DataRowView)Container.DataItem)["Item_Name"] for DataSets, ((DbDataRecord)Container.DataItem)["Item_Name"] for IDataReader.
Anyway, interesting article but this is not the most efficient approach to doing this...
GeneralRe: A couple of small points...this is not the most efficient methodstaffNishant S21 Feb '04 - 1:22 
Thanks for the feedback, Scott! I was not aware of performance issues involved and even if I was, performance was not as important a criteria in my specific requirement.
 
Is this anti-DataBinder.Eval attitude a general sentiment among ASP.NET devs? Or is is just your personal opinion?
 
BTW the primary purpose of the article was the use of "nested" splitters rather than on the proper usage of splitters.
 
Regards
Nish
 

Extending MFC Applications with the .NET Framework [NW]
Summer Love and Some more Cricket [NW] (My first novel)
Shog's review of SLASMC [NW]
Nish is now the first and only CPian (as of now) to reach 16,000 forum posts on CodeProject.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 20 Feb 2004
Article Copyright 2004 by Nish Sivakumar
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid