#1
#2
#3
Questions Answered
Overall Points

ASP.Net - Working with the Repeater control

ASP.Net comes equipped with a whole host of server controls designed specifically for displaying data from a data source. In this article we are going to look at one control in particular - the Repeater. We will look at how to bind a Repeater to a data source, how to control the look and feel of the Repeater using templates, and also how we can customise the appearance based on the data we are binding to.

The Repeater is a "templated" control. What does that mean exactly? It means that we can tell the repeater precisely how we want our data to be displayed by providing a template - a set of HTML tags - that we want it to use for each item in our data source.

The Repeater provides us with five template sections that we can use to define our layout, these are:

HeaderTemplate - The header template will be output once, and only once, when the Repeater is rendered. The markup defined in this template will be output before any data that the Repeater is bound to. It should be worth noting that the header will only be output if we actually have some data to bind to, if we still want to show a header even when there is no data to display we should add the markup before the Repeater control and leave the header template empty.

ItemTemplate - This is the main template for the Repeater control and is the template that will be used for displaying our data. We inject fields from our data source into the template using special data binding tags which will be covered later in the article.

AlternatingItemTemplate - The AlternatingItemTemplate serves the same purpose as the ItemTemplate. The only difference is that this template will be used for alternating items in our data source. This will be covered later in the article if that still sounds a little confusing!

SeparatorTemplate - This template allows us to inject markup between each data item that is rendered using either the ItemTemplate or AlternatingItemTemplate.

FooterTemplate - The footer template will be output once, and only once, when the Repeater is rendered. The markup for the footer template will be output after the last item in the controls data source has been rendered. Just like the header template, the footer template will only be rendered if we have some data to bind to.

Sample Data

Before we dive into the details of defining the repeater itself, lets take a look at our data source. For this article I want to focus on the repeater control itself and not get into the details of connecting to a database - or any other external data - so I am going to use a collection of custom objects to bind to. For this sample I will create a BankAccount class to hold a few basic pieces of data, and then create a List of BankAccount objects which we can then bind to the repeater. The BankAccount class will consist of three automatic-properties for holding the account number, account holders name, and the current balance - and it is defined like:

public class BankAccount
{
	public string AccountNumber { get; set; }
	public string AccountHolder { get; set; }
	public decimal Balance { get; set; }
}

We can then create several instances of the class in a List which we can later use as a data source for the repeater:

List<BankAccount> accounts = new List<BankAccount>()
{
	new BankAccount { AccountNumber = "1234567890", AccountHolder = "Bob Smith", Balance = 100000.00M },
	new BankAccount { AccountNumber = "0001234567", AccountHolder = "Sally Jones", Balance = -100.34M },
	new BankAccount { AccountNumber = "1230001234", AccountHolder = "Jeremy Johnson", Balance = 800.34M },
	new BankAccount { AccountNumber = "0001003456", AccountHolder = "Bruce Guinness", Balance = -80.15M },
	new BankAccount { AccountNumber = "2000012789", AccountHolder = "Delia Thomson", Balance = 1200.00M }
};

Defining the Repeater

Now that we have our sample data ready we can begin to construct our repeater. The first we will do is add some basic style information to our page that will format the various templates. To do this we will add some CSS styles within the <head> element of our page, we will also add an empty repeater control to the page:

<html xmlns="http://www.w3.org/1999/xhtml">
	<head runat="server">
		<style type="text/css">
			.headerFooter { background-color: lightblue; margin: 5px 0px; }
			.accountNumber { background-color: Silver; }
			.accountHolder { float: left; width: 150px; }
			.alt { background-color: lightyellow; }
			span { font-weight: bold; }
		</style>
	</head>
	<body>
		<form runat="server">
			<asp:Repeater ID="AccountRepeater" runat="server">
			</asp:Repeater>
		</form>
	</body>
</html>

We will start by adding the Header, Footer and Separator templates for our repeater. The markup in the header and footer templates will appear before and after our data respectively and the separator markup will be output after each BankAccount object in our data source. After we add these templates our repeater will look like the following:

<asp:Repeater ID="AccountRepeater" runat="server">
	<HeaderTemplate>
		<div class="headerFooter">Active Accounts</div>
	</HeaderTemplate>
	<SeparatorTemplate>
		<hr />
	</SeparatorTemplate>
	<FooterTemplate>
		<div class="headerFooter">This is the footer;</div>
	</FooterTemplate>
</asp:Repeater>

Now we need to add the templates that will be used to display our data. These two templates, ItemTemplate and AlternatingItemTemplate, will do the bulk of the work of displaying our data. We are using an AlternatingItemTemplate in our example because we want to use a different background colour for alternate items (we could also achieve the same effect programmatically without the need for the AlternatingItemTemplate, but using a template keeps a better separation of data and display). The ItemTemplate and AlternatingItemTemplate for our example are defined like:

<ItemTemplate>
	<div>
		<div class="accountNumber">#<%# Eval("AccountNumber") %></div>
		<div>
			<div class="accountHolder"><%# Eval("AccountHolder") %></div>
			<span><%# Eval("Balance") %></span>
		</div>
	</div>
</ItemTemplate>
<AlternatingItemTemplate>
	<div class="alt">
		<div class="accountNumber">#<%# Eval("AccountNumber") %></div>
		<div>
			<div class="accountHolder"><%# Eval("AccountHolder") %></div>
			<span><%# Eval("Balance") %></span>
		</div>
	</div>
</AlternatingItemTemplate>

Notice that these two templates are identical with the exception of the extra class attribute on the first div in the AlternatingItemTemplate.

Data Binding

The main thing that differentiates our ItemTemplate and AlternatingItemTemplate definitions, from the other templates, is the inclusion of data binding tags. These special tags allow us to inject items of data from our data source into the template, and take the format:

<%# Eval("property-name") %>

If you look closely you will notice that there are three data binding tags in our templates, each one corresponding to the name of a property on the BankAccount class that we created earlier. When we run our code these tags will be replaced with the values from the BankAccount object that is being bound to the current row.

Now that we have defined our repeater control, and we have set up our sample data, the only thing left to do is bind our data to the repeater and take a look at the results. To do that we need to add two lines of code to the Load event of our page:

protected void Page_Load(object sender, EventArgs e)
{
	// tell the repeater where to get its data from. In our example this is the List<BankAccount>
	// that we created earlier
	AccountRepeater.DataSource = accounts;

	// tell the repeater to take our data and apply our templates to it
	AccountRepeater.DataBind();
}

If you run the project now you should see five rows of data showing the values from our BankAccount objects. You should see our header and footers displayed above and below our data respectively, and how the AlternatingItemTemplate is being applied for each alternate row. We now have our data displaying but sometimes you will want to add additional formatting based on the actual data being displayed; we will look at how to do that next.

Formatting Our Data

There are a few options available to us for formatting our data. In this demonstration we are going to look at a couple of them. Firstly we are going to use formatters in our markup to display the account balance as a currency, rounded to two decimal places. Secondly we will look at handling the ItemDataBound event for the Repeater control and changing the style of the balance based on its value.

Formatters allow us to control the way that our data is displayed whilst leaving the underlying value in tact. The Eval() method that we used in the ItemTemplate and AlternatingItemTemplate accepts a second parameter that allows us to specify a format for our data. In the markup for our repeater control we simply need to change our definition to:

<%# Eval("Balance", "{0:C2}") %>

And that's it, if we run the application again we should now see that the balance for each of our rows displays a currency symbol and the values are only displaying two decimal places. If you don't see this for all rows make sure that you have changed the Eval() method for both the ItemTemplate and the AlternatingItemTemplate.

The ItemDataBound Event

Our final task is going to be to modify our display so that balances that have a negative value will be highlighted in white text on a red background. To do that we need to be able to examine the data and alter our template based on its value; this is where the ItemDataBound event comes into play.

Before we get to the ItemDataBound event itself, we need to make a couple of changes to our markup in preparation. Firstly we will add a new style that we will use for negative balance:

.overdrawn { background-color: red; color: white; }

Secondly we will need to access the for our balance from code-behind. In order to do this we need to convert it to a HTML Server Control, which we do by changing the markup for the balance to (again, be sure to do this for both the ItemTemplate and AlternatingItemTemplate):

<%# Eval("Balance", "{0:C2}") %>

Next we need to attach a delegate to the ItemDataBound event of the repeater control. We will do this programmatically, so go ahead and the following line to the top of the Page_Load method:

AccountRepeater.ItemDataBound += new RepeaterItemEventHandler(AccountRepeater_ItemDataBound);

Finally we are ready to implement the event handler itself. We need to do a few things in our event handler; firstly we need to check what type of row is currently being bound. If it is an Item or AlternatingItem then we need to retrieve the data associated with the row and cast it to a BankAccount object. We will then check the Balance property and, if it is a negative value, we need to locate the HTML Server Control (the one we created by adding the ID and runat attributes to our span) and set its style.

Phew! To do all of that we need to add the following method to our code behind:

protected void AccountRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
	// first, check that we are dealing with an Item or AlternatingItem row
	if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
	{
		// next we need to cast the DataItem for the row to a BankAccount object
		// and check if its Balance is below zero
		BankAccount account = e.Item.DataItem as BankAccount;
		if (account.Balance < 0.0M)
		{
			// use FindControl to locate our HTML Server control and add a "class" attribute to it
			System.Web.UI.HtmlControls.HtmlGenericControl control = e.Item.FindControl("BalanceSpan") as System.Web.UI.HtmlControls.HtmlGenericControl;
			control.Attributes.Add("class", "overdrawn");
		}
	}
}

If we run the application now we should see that the two rows in our data that had a negative balance are now highlighted in red and white.

And that's it! The repeater control offers a lot of power and flexibility for laying out and customising data, and we have really only scratched the surface of what is possible in this article. But hopefully this demonstration will have helped to shed a little light on how to start working with this powerful control.

Comment on this article
(required)
(required)
(optional)

What other people have said