Introduction:
In this article we will see that how we can use
the nested repeaters to display information in a categorized way. We will use the Northwind database and will learn to display the information in the
Categories and in the Products table in a categorized way.
What is categorized way?
Most of you might be thinking what does
categorized data means. To have a better picture take a look at the screen shot
of the ArticleCategory.aspx page of the GridViewGuy. To view this page simply
browse to the GridViewGuy website and click on the Articles link contained in
the menu on the left.

As, you can see from the screenshot above that all the
articles are well placed in their respective categories. This is what I refer to
as displaying the data in a categorized way.
The Database:
In this article we will be using the Northwind
database. The stored procedure is given below which gets the Categories and the
Products from the Northwind database tables.
CREATE PROCEDURE [usp_GetProductsForCategories]
AS
SELECT * FROM Categories WHERE CategoryID IN
( SELECT CategoryID FROM Products )
SELECT p.ProductID, p.ProductName,p.CategoryID FROM Products p
|
The stored procedure returns two sets. The first set contains
all the columns of the Categories table which have the corresponding record in the
Products table. The second set contains the ProductID, ProductName and the
CategoryID from the Products table. We will use the DataSet Relation to join the
two sets together.
Setting up the Repeater Controls:
Now, let's take a look at the Repeater controls which are used
to display the data on the screen. We will be using nested repeaters for our
scenario. The outer repeater will display the category name and the inner
repeater will display the articles related to that category. Take a look at the
code below which creates the outer repeater control.
| <asp:Repeater
ID="outerRep"
runat="server"
OnItemDataBound="outerRep_ItemDataBound">
<ItemTemplate>
<div>
<asp:Label
Font-Size="Large"
Font-Bold="true"
ID="lblCategoryName"
runat="server"
Text='<%#
Eval("CategoryName") %>'
/>
</div>
</asp:Repeater> |
The outer repeater which is defined as "outerRep" contains a
simple Label control which is used to display the category name from the
database. Now, let's see the inner repeater which will be used to display the
products of the corresponding category.
| <asp:Repeater
ID="outerRep"
runat="server"
OnItemDataBound="outerRep_ItemDataBound">
<ItemTemplate>
<div>
<asp:Label
Font-Size="Large"
Font-Bold="true"
ID="lblCategoryName"
runat="server"
Text='<%#
Eval("CategoryName") %>'
/>
</div>
<asp:Repeater
ID="innerRep"
runat="server">
<ItemTemplate>
<div
style="background-color:AliceBlue">
<asp:HyperLink
ID="hlProductName"
runat="server"
Text='<%#
Eval("ProductName") %>'
/>
</div>
</ItemTemplate>
</asp:Repeater> |
The inner repeater which is defined as "innerRep" contains a
simply ASP.NET HyperLink control which displays the product name as a link.
The example above does not display the HyperLink control as
a clickable link since, I have not bound any field to the NavigateUrl property
of the HyperLink control. If you have a link field in your database table you
can easily bind that link field to the NavigateUrl property and it will be
rendered as a link.
Populating the Repeaters:
The last and the most important step is to populate the
Repeater controls. Take a look at the BindData method which populates the
DataSet and create relationship on the DataSet.
| private
void BindData()
{
SqlConnection
myConnection = new
SqlConnection(ConnectionString);
SqlCommand
myCommand = new
SqlCommand("usp_GetProductsForCategories",
myConnection);
myCommand.CommandType = CommandType.StoredProcedure;
SqlDataAdapter
ad = new
SqlDataAdapter(myCommand);
DataSet ds =
new
DataSet();
ad.Fill(ds);
// Attach the relationship to the
dataSet
ds.Relations.Add(new
DataRelation("CategoriesRelation",ds.Tables[0].Columns["CategoryID"],
ds.Tables[1].Columns["CategoryID"]));
outerRep.DataSource = ds.Tables[0];
outerRep.DataBind();
} |
We have used the SqlDataAdapter to fill the DataSet container.
Once, the DataSet is filled the relationship is created between the Table[0]
(Categories) and the Table[1] (Products). Finally, the Categories table is
assigned to the outer repeater control.
What about the Populating the Inner Repeater?
The technique that I have used to populate the inner repeater
is to utilize the Item_DataBound event of the outer repeater. Check out the
Item_DataBound event of the outer repeater control.
|
protected void
outerRep_ItemDataBound(object
sender, RepeaterItemEventArgs
e) {
if (e.Item.ItemType
== ListItemType.Item
||
e.Item.ItemType == ListItemType.AlternatingItem)
{
DataRowView
drv = e.Item.DataItem as
DataRowView;
Repeater
innerRep = e.Item.FindControl("innerRep")
as
Repeater;
innerRep.DataSource = drv.CreateChildView("CategoriesRelation");
innerRep.DataBind();
} |
First, we check that if the row belong to the ItemTemplate or
the AlternatingItemTemplate. Then we get a DataRowView object of the current
data item. We find the inner repeater control using the FindControl method of
the current item. And finally assign the DataView which is returned from the
CreateChildView method of the DataRowView object. Take a look at the screenshot
below to have a clear idea of what the output looks like.

As, you can see from the image above all the products are
displayed in the correct categories.
Conclusion:
The article explained that how easily you can use the DataSet
Relations to create relations between two tables. Although a DataSet is quite
simple to use but it is a heavy container and should be used wisely. I highly
recommend using entity classes and collections for the same purpose.
I hope you liked the article, happy coding!