Wednesday, April 4, 2012

ListView and DataPager Controls: Grouping Data with the ListView Control


Introduction


ASP.NET version 3.5 added two new data Web controls to the Toolbox: the ListView and DataPager. As discussed in the first installment of this article series, Displaying Data with the ListView, the ListView control offers the same built-in features found in the GridView, but much finer control over the rendered output. The ListView's output is defined using a variety of templates, and we looked at examples using the control's LayoutTemplate and ItemTemplates. In particular, these examples used a LayoutTemplate that included a placeholder for the ItemTemplate's rendered output.
The ItemTemplate is rendered for each record bound to the ListView control, and is typically referenced in the LayoutTemplate. This approach generates the rendered markup defined in the LayoutTemplate, plus the rendered markup created by the ItemTemplate for each record. This works fine for simple rendering scenarios, but in more complex scenarios we may need to render different formatting markup for different groups of records. For example, imagine that we needed to display a set of records in a three-column HTML <table>. For each record we would want to emit a table cell (<td>), but for every three records we would need to emit a new table row (<tr>). Such customizations can be accomplished declaratively with the ListView control's includes GroupTemplate andGroupItemCount properties.
In this article we will see how to use the GroupTemplate and GroupItemCount properties to instruct the ListView control to render different encasing markup for every n records. We will look at two demos: one that renders records into a series of ordered lists, and another that illustrates how to display data in a multi-column table. Read on to learn more!

Grouping Basics


As we saw in the Displaying Data with the ListView article, the ListView control contains two requisite templates: LayoutTemplate and ItemTemplate. The LayoutTemplate is rendered to generate the ListView control's markup and can contain a reference to the ItemTemplate, which is used to render each record bound to the ListView control. The LayoutTemplate references the ItemTemplate through a server-side control (such as the PlaceHolder control) whose ID is the same as the ListView's ItemPlaceholderID property. (The ItemPlaceholderID property has a default value of "itemPlaceholder".)
Referencing the ItemTemplate directly from the LayoutTemplate works well if the encasing markup for each item is the same, but in several scenarios different encasing markup may need to be introduced every n items. Such customization is possible by defining a GroupTemplate and setting the ListView control's GroupItemCount property to n. Then, instead of referencing the ItemTemplate in the LayoutTemplate, have the LayoutTemplate reference the GroupTemplate, and the GroupTemplate reference the ItemTemplate. Such a setup still has the ItemTemplate rendered for every record bound to the ListView control, but causes the GroupTemplate to be rendered every GroupItemCount number of records.
To better understand how grouping with the ListView control works, let's take the first example we examined in the Displaying Data with the ListView article and extend it to use grouping. The first example illustrated how to display a set of records in an ordered list, and used the following declarative markup for the ListView control:
<asp:ListView ID="..." runat="server" DataSourceID="...">
   <LayoutTemplate>
      <ol>
         <asp:PlaceHolder runat="server" ID="itemPlaceholder"></asp:PlaceHolder>
      </ol>
   </LayoutTemplate>

   <ItemTemplate>
      <li><%# Eval("columnName") %></li>
   </ItemTemplate>
</asp:ListView>

Imagine, however, that we want to display an ordered list for each group of three records. To accomplish this use the following markup instead:
<asp:ListView ID="ProductList1" runat="server"
   DataSourceID="ProductDataSource"
   GroupItemCount="3" ItemPlaceholderID="itemsGoHere"
   GroupPlaceholderID="groupsGoHere">

   <LayoutTemplate>
      <p>
         <asp:PlaceHolder runat="server" ID="groupsGoHere"></asp:PlaceHolder>
      </p>
   </LayoutTemplate>

   <GroupTemplate>
      <ol>
         <asp:PlaceHolder runat="server" ID="itemsGoHere"></asp:PlaceHolder>
      </ol>
   </GroupTemplate>

   <ItemTemplate>
      <li><%#Eval("ProductName")%></li>
   </ItemTemplate>
</asp:ListView>

The ListView control's declarative markup is nearly the same as in the previous article, but instead of the <ol> element being in the LayoutTemplate, it has been moved to the GroupTemplate. The ItemTemplate has reamined the same. Note, however, that the LayoutTemplate still must be present and now references the GroupLayout. Also note that instead of the default values for the group and item placeholders ("groupPlaceholder" and "itemPlaceholder") I have explicitly changed these values through the ListView control's ItemPlaceHolderID and GroupPlaceholderID properties.
Imagine that the above ListView is bound to an employees database table, and that in the ItemTemplate we were rendering the FullName column within the <li> element. What would the ListView's rendered markup look like?
Well, the ListView would start by rendering it's LayoutTemplate:
<p>
   <asp:PlaceHolder runat="server" ID="groupsGoHere"></asp:PlaceHolder>
</p>

It would then render its GroupTemplate for each group of three records bound to the ListView control. Assuming that there were eight total employees, this would result in the following markup:
<ol>
  <asp:PlaceHolder runat="server" ID="itemsGoHere"></asp:PlaceHolder>
</ol> 


<ol>
  <asp:PlaceHolder runat="server" ID="itemsGoHere"></asp:PlaceHolder>
</ol>

<ol>
  <asp:PlaceHolder runat="server" ID="itemsGoHere"></asp:PlaceHolder>
</ol>

It would then render its ItemTemplate for each record bound to the ListView control. This might result in the following markup:
<li>Scott Mitchell</li>
<li>Sam Smith</li>
<li>Jisun Lee</li>
<li>Andrew Fuller</li>
<li>Edgar Johnson</li>
<li>Ellen Plank</li>
<li>Tito Wald</li>
<li>Layla Clapton</li>

The ItemTemplates' rendered markup would be placed in the appropriate GroupLayout PlaceHolder controls. The net result is the following markup:
<p><ol><li>Scott Mitchell</li>
<li>Sam Smith</li>
<li>Jisun Lee</li>
</ol><ol>
<li>Andrew Fuller</li>
<li>Edgar Johnson</li>
<li>Ellen Plank</li>
</ol>
<ol><li>Tito Wald</li>
<li>Layla Clapton</li>
</ol></p>

Displaying Data in a Multi-Column Table


Displaying records in a multi-column table is a very common scenario, and is one that requires rendering different formatting markup for groups of records. Oftentimes, such formatting is achieved through the use of a multi-column HTML <table>. For example, to display a three-column table, we would render three table cells (<td>) in each table row (<tr>), like so:
<table ...>
   <tr>
      <td>Record 1</td>
      <td>Record 2</td>
      <td>Record 3</td>
   </tr>

   ...

   <tr>
      <td>Record N - 2</td>
      <td>Record N - 1</td>
      <td>Record N</td>
   </tr>
</table>

In order to generate such markup with a ListView control, we need to use a LayoutTemplate that renders the outer <table> and </table> tags, a GroupTemplate that renders the table row elements, and an ItemTemplate that renders each table cell. The following declarative markup illustrates how to display data in a three-column table:
<asp:ListView ID="ProductDataList2" runat="server"
   DataSourceID="..." GroupItemCount="3">
  
   <LayoutTemplate>
      <table>
         <tr>
            <td>
               <table border="0" cellpadding="5">
                  <asp:PlaceHolder runat="server" ID="groupPlaceHolder"></asp:PlaceHolder>
               </table>
            </td>
         </tr>
      </table>
   </LayoutTemplate>

   <GroupTemplate>
      <tr>
         <asp:PlaceHolder runat="server" ID="itemPlaceHolder"></asp:PlaceHolder>
      </tr>
   </GroupTemplate>

   <ItemTemplate>
      <td>
         <h2><%# Eval("ProductName") %></h2>
        
         Price: <%#Eval("UnitPrice", "{0:c}")%><br />
         Category: <%# Eval("CategoryName") %>
      </td>
   </ItemTemplate>
</asp:ListView>

The download available at the end of this article includes a demo that displays the records from the Northwind database's Products table in a three-column table, which yields the following when viewed through a browser.

Conclusion


In this article we examined how to render output batched into a specified group size using the ListView control's GroupTemplate and GroupItemCount property. This template and property are useful in scenarios where the formatting layout needs to change for every n rendered records, such as when displaying a multi-column table. Prior to the ListView control, such grouping required the page developer to write code that would intelligently inject additional formatting markup for every n records. But with the ListView control's GroupTemplate and GroupItemCount property, group formatting is now possible entirely through declarative means.
Happy Programming!
  • By Scott Mitchell

    Further Readings:
  • An Overview of ASP.NET 3.5 and Visual Studio 2008
  • The asp:ListView Control (Part 1)
  • Displaying Data with the ListView
  • Attachments


  • Download the Demo (in ZIP format)
    Reference
  • http://www.4guysfromrolla.com/articles/010208-1.aspx
  • No comments:

    Post a Comment