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.

Live DemoDownload

ListView Overview

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. 

And another high-level summary of the control from Scott Guthrie ...

 

ListView's ItemTemplate

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'.

ListView's LayoutTemplate

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 LayoutTemplateMSDN 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:

  1. Determines what column index is currently being sorted by
  2. Adds the sortasc or sortdesc class to the TH cell in the header row for the column that is being sorted by
  3. 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. 

CSS Classes

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.

Complete Markup

What Else?

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!


TrackBack

TrackBack URL for this entry:
http://mattberseth.com/blog-mt/mt-tb.fcgi/89

Listed below are links to weblogs that reference YUI DataTable Styled ListView:

» 推荐系列:2008年第04期 总6期 from TerryLee
概述1.FiveAjaxControlToolkitTabThemescreatedfromDynamicDrive.com [Read More]

Comments


Posted by: Vish on November 25, 2007 12:00 AM

Hi Matt,
Thanx for the article,
I was trying the same thing but applying igoogle themes instead of YUI Datatable.

Posted by: shaobing cheng on November 26, 2007 12:00 AM

Hi matt,your series posts about GridView and Listview control are very great!

Since with the new Listview control we can have much more control over how the HTML for the control is rendered, My Question is :
Is there possible for rending a html table using a style just like "TreeList"? Sometiem well encounter such situation that we should group the data of the grid or list and then collapse or expand it.Think about the project management product such as MS Project how to display the workitem according the WBS code. thks!

Hi Matt,

Another great article. One addition: if you used the ListView in the pre-RTM versions of VS 2008 (that is, beta1 and beta2), please note that the notation for the placeholderID in the ListView has changed.

In the beta you assigned .

In the RTM this has changed to ID="itemPlaceholder", as listed in your post. (In the )

This took me some time to find in the RTM and I had some refactoring to do in order to upgrade and run my previous projects in the RTM version of VS2008.

Thanks,
Peter.

@Vish -

Nice. I would be interested in seeing your examples.

Matt.

@shaobing cheng
It certainly seems like the ListView has the flexibility to do something like this.

Matt.

@Peter

Good tip. Its those subtle changes that take forever to track down.

Matt.

Posted by: Amr on November 27, 2007 12:00 AM

Hello Matt,
I am one of your blog fans keep on it.

Off Topic: How Do make images get the shadow I really like it can you tell me how.

Wow! Awesome!

@Amr -

I use WinSnap. Its not free, but it does a pretty good job.

Thanks,
Matt

Posted by: Steve on December 1, 2007 12:00 AM

Good article - .net makes building javascript components to be very unnatural.

I look forward to using YUI grids with MS MVC - I know I use them with Monorail and they are so much easier to use outside of the webform model.

Hopefully MS will find ways to use this new Listview in their MS MVC release

Great article. Listview control is cool in .net 3.5.

Posted by: Mike Ramsey on February 6, 2008 12:00 AM

GREAT Article.

I just want to add for anyone that may be using VB instead of C# that in the ItemTemplate tr,
Container.DataItemIndex % 2 == 0 ? "row" : "altrow" will not work. Instead use
IIf(Container.DataItemIndex Mod 2 = 0, "alt", "")

Thanks for the article. The example works well on its own. However trying to adapt it into a site with nested master pages we have here causes the code in the ItemDataBound handler to fail as the FindControl call can no longer locate the table. Digging through it looks like the naming of the child objects in the list view is getting mangled. Any suggestions as to a workaround?

Posted by: Jeanne Vural on June 20, 2008 12:00 AM

I have also switched from using repeater and gridview to the listview. However i am having trouble with z-order of "yuimenubar yuimenubarnav" class and the listview header. It seems the menu appears behind the header no matter what I have tried. Any suggestions?

Great information... thanks for visual explanation

Posted by: Jim on September 13, 2008 11:35 AM

I would love to see a VB version of this. Can anyone help?

Regards

Jim

Posted by: Jason Parry on September 16, 2008 08:37 AM

Private _sortCellIndex As System.Nullable(Of Integer)

Protected Sub myListView_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewItemEventArgs) Handles myListView.ItemDataBound
Dim listView As ListView = DirectCast(sender, ListView)

' if there is no sort expression, don't bother
If listView.SortExpression.Length > 0 Then
' if this is the first time ItemDataBound has fired, figure out what column
' is being sorted by
If Not Me._sortCellIndex.HasValue Then
Dim header As HtmlTableRow = DirectCast(listView.FindControl("header"), HtmlTable).Rows(0)
For i As Integer = 0 To header.Cells.Count - 1

' loop through the cells and find the one that contains the linkbutton
' with the commandargument of the ListView's current SortExpression
Dim th As HtmlTableCell = header.Cells(i)
' find the LinkButton control
For Each c As Control In th.Controls
Dim linkButton As LinkButton = TryCast(c, LinkButton)
If linkButton IsNot Nothing AndAlso linkButton.CommandArgument = listView.SortExpression Then
' keep track of the cell index
Me._sortCellIndex = i

' add the sort class to this item
Dim originalHeaderStyle As String = th.Attributes("class")
th.Attributes("class") = String.Format("{0} {1}", originalHeaderStyle, IIf(listView.SortDirection = SortDirection.Ascending, "sortasc", "sortdesc")).Trim()
Exit For
End If
Next
Next
End If

' set the cells css class as well
Dim tr As HtmlTableRow = DirectCast(e.Item.FindControl("row"), HtmlTableRow)
Dim td As HtmlTableCell = tr.Cells(Me._sortCellIndex.Value)
Dim originalCellStyle As String = td.Attributes("class")
td.Attributes("class") = String.Format("{0} {1}", originalCellStyle, "sort").Trim()
End If

End Sub

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Consulting Services

Yep - I also offer consulting services. And heck, I'll do just about anything. If you enjoy my blog just drop me an email describing the work you need done.

Recent Comments

  • Jason Parry wrote: Private _sortCellIndex As System.Nullable(Of Integer) Protected Sub myListView_ItemDataBound(B...
  • Jim wrote: I would love to see a VB version of this. Can anyone help? Regards Jim...
  • ASP Net Web Development wrote: Great information... thanks for visual explanation...
  • Jeanne Vural wrote: I have also switched from using repeater and gridview to the listview. However i am having trouble w...
  • Richard wrote: Thanks for the article. The example works well on its own. However trying to adapt it into a site wi...
  • Mike Ramsey wrote: GREAT Article. I just want to add for anyone that may be using VB instead of C# that in the ItemTe...
  • Jerome Chen wrote: Great article. Listview control is cool in .net 3.5. ...
  • Steve wrote: Good article - .net makes building javascript components to be very unnatural. I look forward to us...