YUI DataTable Styled ListView
Now that .Net 3.5 and VS 2008 have shipped, I thought it would be a good time to take a look at the new ListView control. I use the GridView quite frequently, and I am curious what the tradeoffs I would encounter if I used the new ListView control for rendering our tabular datasets. I figured a good way to learn would be to create a ListView that generates one of my favorite looking HTML tables.
So I re-implemented my existing YUI DataTable Styled GridView using the ListView. My main goal for this task is just to get a better feeling for how the ListView control works. Unfortunately my asp.net hosting service won't support .Net 3.5 until sometime next week so until then there isn't a demo. But you can download the code for this sample.
If you aren't familiar with the ListView control, here is a quick overview from MSDN. I read this article end to end and found it very useful. Well worth the time investment.
The ListView's ItemTemplate is the mechanism used for the rendering of the collection of data items the control is bound to. The sample I created for this post displays 5 rows of customer data, the ItemTemplate is the template each of these 5 rows are run through to generate the markup for the data item portion of the control. If you are familiar with the GridView, the ItemTemplate is similar to the Columns collection of the GridView. This is where you will use the data binding syntax to bind the values of the attributes from your datasource to their corresponding UI elements. So, for my YUI DataTable Styled GridView, my Columns collection looked like this ...
<Columns> <asp:BoundField HeaderText="ID" DataField="customerid" SortExpression="customerid" /> <asp:BoundField HeaderText="Company" DataField="companyname" SortExpression="companyname" /> <asp:BoundField HeaderText="Contact Name" DataField="contactname" SortExpression="contactname" /> <asp:BoundField HeaderText="Contact Title" DataField="contacttitle" SortExpression="contacttitle" /> <asp:BoundField HeaderText="Country" DataField="country" SortExpression="country" /> <asp:BoundField HeaderText="Phone" DataField="phone" SortExpression="phone" /> </Columns>
With the ListView, I have much more control over how the HTML for the control is rendered. For this sample, I want my customer attributes to be rendered as text within the TD element's of a table. Check out the code snippet below that makes up the ItemTemplate.
<ItemTemplate> <tr id="row" runat="server"> <td><%# Eval("customerid") %></td> <td><%# Eval("contactname")%></td> <td><%# Eval("contacttitle")%></td> <td><%# Eval("country")%></td> <td><%# Eval("phone")%></td> </tr> </ItemTemplate>
Which at runtime will be rendered like this for the row where customerid is equal to 'BERGS'.
Now that the template for the individual items is created, we can build the template for the rows parent table. This is defined within the ListView's LayoutTemplate. MSDN uses the phrase 'root template' to define the LayoutTemplate. Basically this template is used to create the main (or root) layout for the control. For my example I want my ListView to render as an HTML table, so this template will no doubt be comprised of a <table> element. However, there is nothing restricting you to this. You can just as easily build a <ul> or a structure of <div>'s.
Whatever html you want the ListView to render, you will most likely need the LayoutTemplate and ItemTemplate to be in sync. This is because the LayoutTemplate contains a special placeholder item that is replaced with the markup that is generated from your ItemTemplate. So in this example, my LayoutTemplate contains a html table with 2 child rows, one that defines the header cells, and another that is a placeholder for the databound rows. When the ListView renders, the placeholder is replaced with what is generated from the ItemTemplate being bound to each of the items in the datasource.
Below is the markup for the LayoutTemplate for this sample. Notice how there are 2 rows, one that has LinkButtons in each of the TH elements - this is the header row. The row circled in red is the placeholder row that will be replaced at runtime with the output of the markup that is generated by running each of the databound items through the ItemTemplate that was created in the previous step.
If you notice the TR element that represents the placeholder has an ID of 'itemPlaceholder'. This is not by accident, the ListView will look for an item with this ID by default. If you want to provide a different ID, you can specify it using the ItemPlaceholderID attribute.
With the ItemTemplate and LayoutTemplate we have created most of the styles required for the YUI Styled DataGrid. Now we will move on to adding the sorting related features.
ListView's Sort Command
Like the GridView, the ListView supports a number of well-known or intrinsic commands, one of which is Sort. Below is a table that summarizes the intrinsic commands for the ListView.
Below is a blurb from MSDN that does a good job of summarizing how sorting works with the ListView. If you look back at the markup for the LayoutTemplate you will notice that all of the LinkButtons have the CommandName attribute set the Sort and the CommandArgument set to the name of the property on my databound item that I want to sort by.
ListView ItemDataBound Event
Well, everything has gone pretty smooth so far. Now for the difficult part. I want to toggle the classes of the individual TH and TD elements that are participating in the current column's sort. So when the user sorts by Contact Title, I want to display an icon in the header cell, a different background image in the header cell and different background colors for that column's data cells.
To handle all of this, I handled the ListView's ItemDataBound event and ran a bit of code that does the following:
- Determines what column index is currently being sorted by
- Adds the sortasc or sortdesc class to the TH cell in the header row for the column that is being sorted by
- Adds the sort class to the TD cells for the data rows
Once that bit of code is in place, I defined the styles for all of the css classes my ListView generates.
To support my presentation requirements, I created the following CSS style rules.
Basic Header Style Rules
Header Sort Style Rules
Data Row and Cell Style Rules
How Does it Render?
Like a Champ. Check it out. I collapsed some of the data rows, but I think you get the picture. Notice the 4th column, the TH element has the sortdesc class applied to it and the TD element has the sort class applied.
Well, with this bit of research, I hit feature parity with my original YUI DataTable Styled GridView. But building this example left me with that tip of the iceberg feeling. What about ...
- Adding Paging support with the new DataPager control
- The other templates for Grouping, Editing and Inserting?
- EmptyDataTemplate for empty datasources (no more ShowHeaderWhenEmpty?)
- Having my GridViewControlExtender work with a the <table> or <ul> generated by the ListView
- Implementing frozen headers using one of these techniques (here, here and here)
That's it. Enjoy!