Scott Muc

Another .Net Developer Named Scott

  Home  |   Contact  |   Syndication    |   Login
  29 Posts | 0 Stories | 27 Comments | 4 Trackbacks

News

Archives

Post Categories

Blogging Tools

Personal

Work Related

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?

posted on Thursday, March 22, 2007 7:10 PM