I have a class that contains hierarchical data. I want to present this data in my ASP.net webapp using nested repeaters. How do I do this? I've only ever done one level of nesting, how do I do say five levels?
Each item can have zero or many sub items. I'm basically just indenting at each subleveling using some css stuff. I do not want to use the treeview control, I want to strictly stick with a repeater.
Update:
My data comes from a database. I have an item datatable with some basic properties.
Item { ID, Name, Description, ... }
Then I have a many to many table with:
Parent { ParentID, ChildID }
I'm iterating through each item and displaying its children; and its children's children. I assume this would best be accomplished with nested repeaters, but I could be wrong.
For accessing the inner repeater control you'll need to make use a RepeaterItem class that will help you to access the inner repeater control or any control that is placed inside the ItemTemplate or FooterTemplate or AlternatingItemTemplate class, by using the FindControl method of the RepeaterItem class.
In the parent repeater, attach a method to the OnItemDataBound event and in the method, find the nested repeater and data bind it. Always find it odd when ItemDataBound is used for this.
The Repeater control is used to display a repeated list of items that are bound to the control. The Repeater control may be bound to a database table, an XML file, or another list of items. Repeater is a Data Bind Control. Data Bind Controls are container controls.
I've found that the simplest way to do nested repeaters without worrying about databinding events is to just set the DataSource using <%# %>
syntax.
For example:
<asp:Repeater runat="server" id="Departments"> <ItemTemplate> Name: <%# Eval("DeptName") %> Employees: <asp:Repeater runat="server" DataSource='<%# Eval("Employees") %>'> <ItemTemplate><%# Eval("Name") %></ItemTemplate> <SeparatorTemplate>,</SeparatorTemplate> </asp:Repeater> </ItemTemplate> </asp:Repeater>
This is presuming that your Departments class has an Employees property - eg:
public class Department { public string DeptName {get; set;} public IEnumerable<Employee> Employees {get; set;} } public class Employee { public string Name {get; set;} }
If your outer-repeater object doesn't have a property corresponding to the inner-repeater object you can still use this trick, by adding a method in your code-behind that does the calculation. So your inner repeater might become:
<asp:Repeater runat="server" DataSource='<%# GetEmployees(Container.DataItem) %>'>
and then GetEmployees might look something like:
protected IEnumerable<Employee> GetEmployees(object item) { var dept = (Department) item; // then do whatever is necessary to get the employees from dept return employees; }
It's always cleaner to deal with the datasource than messing about with ItemDataBound, but this is even more the case when nesting Repeaters:
<asp:Repeater DataSource="<%#ColOfCol%>" runat="server"> <ItemTemplate> <tr> <asp:Repeater DataSource="<%#Container.DataItem%>" runat="server"> <ItemTemplate> <td><%#SomeExtractingMethodLikeEval()%></td> </ItemTemplate> </asp:Repeater> </tr> </ItemTemplate> </asp:Repeater>
The inner datasource could also be an evaluated property, or a call to a method that returns the enumeration wanted. Just be aware that it will be called with an object. I prefer to write the specific version, and then overload:
protected IEnumerable<string> GetNames(Family fam) { foreach(Person p in fam.Members) yield return p.FirstName + " " + p.Surname; } protected IEnumerable<string> GetNames(object famObj) { return GetNames((Family)famObj); }
One thing to be aware of is that if you want to get the current object in the parent repeater than you have to obtain it with:
((RepeaterItem)Container.Parent.Parent).DataItem
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With