I'm a firm believer that using the
Repeater control is the best compromise in flexibility and ease of use for displaying
collections of data. Much of my databinding code looks like the following real world example:
CodeBehind
void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Collection<Venue> venues = ConcertDataService.GetVenues();
rptVenues.DataSource = venues;
rptVenues.DataBind();
}
}
.aspx or .ascx
<asp:Repeater id="rptVenues" runat="server">
<HeaderTemplate><div class="venues"></HeaderTemplate>
<ItemTemplate>
<div>
<%# ((Venue) Container.DataItem).Name %>
<%# ((Venue) Container.DataItem).Address.City %>, <%# ((Venue) Container.DataItem).Address.Province %>
</div>
</ItemTemplate>
<FooterTemplate></div></FooterTemplate>
</asp:Repeater>
Today I refactored
some code so I could get rid of the Addresses table in
the database. To make a long story short, the Address table wasn't working
the way I anticipated. Triggers are required to create and delete address
tuples, and the whole design had lots of
code smells. I merged the columns of the address table into the Venues table and eleminated 3 stored procedures,
2 triggers, and 1 join inside a view. I got rid of the Address class and
attempted to re-compile my code. As expected, my code broke at all Venue
code where I was using the Address class. I simply converted the Address
properties into properties of the Venue class. It didn't take long to update
the code so that I am using Venue.City instead of Venue.Address.City.
All good, right? I deploy my binaries to my development site and I start
getting exceptions on certain pages. Invalid properties?! Oh, but of
course. Compiling the codebehind doesn't ensure that the .aspx pages are
not broken. The fix is trivial, but compile time discovery of these errors
would be nice. The following databind code shows the difference:
.aspx or .ascx
<asp:Repeater id="rptVenues" runat="server">
<HeaderTemplate><div class="venues"></HeaderTemplate>
<ItemTemplate>
<div>
<%# ((Venue) Container.DataItem).Name %>
<%# ((Venue) Container.DataItem).City %>, <%# ((Venue) Container.DataItem).Province %>
</div>
</ItemTemplate>
<FooterTemplate></div></FooterTemplate>
</asp:Repeater>
Luckily I am working on a fairly small project so I only had a half a
dozen .aspx and .ascx files to update (and TextPad's "Find in Files" feature
really did most of the work).
On the way home on the bus I thought about the work I had to go through
to perform this refactoring. Is explicit property calls in the .aspx a
good idea? Second, I wouldn't have had this problem if I kept the Address
class hidden and used Venue properties in the first place. Let's ignore
the fact that I implemented the class incorrectly ;-).
Would using Web/User controls inside the Repeater be a better way
of implementing this behaviour? If I had done it that way, the
compiler would have caught the missing properties. Here's my alternate
implementation:
CodeBehind
void Page_Init(object sender, EventArgs e)
{
rptVenues.ItemDataBound += new RepeaterItemEventHandler(rptVenues_ItemDataBound);
}
void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Collection<Venue> venues = ConcertDataService.GetVenues();
rptVenues.DataSource = venues;
rptVenues.DataBind();
}
}
void rptVenues_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Venue venue = (Venue) e.Item.DataItem;
Literal litName = (Literal) e.Item.FindControl("litName");
Literal litCity = (Literal) e.Item.FindControl("litCity");
Literal litProvince = (Literal) e.Item.FindControl("litProvince");
litCity.Text = venue.City; // used to be venue.Address.City
litProvince.Text = venue.Province // used to be venue.Address.Province
}
}
.aspx or .ascx
<asp:Repeater id="rptVenues" runat="server">
<HeaderTemplate><div class="venues"></HeaderTemplate>
<ItemTemplate>
<div>
<asp:Literal id="litName" runat="server" />
<asp:Literal id="litCity" runat="server" />, <asp:Literal id="litProvince" runat="server" />
</div>
</ItemTemplate>
<FooterTemplate></div></FooterTemplate>
</asp:Repeater>
What's changed is that I now have code in the ItemDataBound event handler
for the repeater. It's a lot of extra code, but it does allow a lot of
room for future changes without much front end adjustment. Recompiling will
find errors in the class structure which I really love.
It's sort of a toss up for me. I love the quick and simple data binding
in the ItemTemplate of the Repeater, but after refactoring a bunch
of aspx files today I might turn a new leaf. Has anyone else dealt with
this sort of issue? What are your thoughts?