Using Formatting Functions with GridView/Template Field

by Gong Liu February 05, 2009 15:32

This article is also published on The Code Project

A TemplateField of a GridView control offers certain level of flexibility to combine data fields and format them for display. For example, we can use a TemplateField to display FirstName and LastName in a single GridView column, and even add a link to the combined column. However, if the formatting is too complex, using a formatting function with a TemplateField is the way to go.

Let's explore the ways to use formatting functions in the following example, where our data source is a table of POIs (points of interest) resulted from a spatial search, and the table includes these data fields:

  • POIName
  • Address
  • City
  • County
  • State
  • Zip
  • Country
  • Phone
  • CatCode (Category Code)
  • Latitude
  • Longitude
  • Distance (Distance from search center)

What we want to display to a user is (see screenshot at the end of this post):

  • The POIName field with a link to show the POI on Google Maps based on the POI's Latitude and Longitude fields
  • A single Address field which combines Address, City, County, State, Zip, and Country fields
  • The Phone field
  • The CatCode field
  • The Distance field

The first two fields are of particular interest. To display the POIName field with a link to Google Maps, we can use the following TemplateField:

<asp:GridView ID="gvwResults" runat="server" AutoGenerateColumns="False"
  EmptyDataText="No result found." CellPadding="2" EnableViewState="False">
    <asp:TemplateField HeaderText="POI Name">
        <asp:LinkButton ID="LinkButton1" runat="server" title="map it"
          PostBackUrl="<%# GoGoogleMaps(Eval(&quot;Latitude&quot;),
          Eval(&quot;Longitude&quot;)) %>">
          <%# Eval("POIName") %>

The TemplateField contains a LinkButton server control. The LinkButton control's text is the POIName field, and its PostBackUrl attribute is bound to the formatting function GoGoogleMaps with Latitude and Longitude fields as input parameters. Notice that we have to use the xml entity &quot; to surround a data field name because we can't have double quotes within double quotes. The formatting function GoGoogleMaps looks like this in C#:

protected string GoGoogleMaps(object lat, object lon)
    if (Convert.IsDBNull(lat) || Convert.IsDBNull(lon))
        return null;
        return string.Format(
            "{0},{1}&z=15", lat, lon);

The Eval method of DataBinder class always evaluates a data field to an object and that's why we declare so for all parameters of the formatting function. The latitude and longitude fields of a POI could be null, and if so, we simply don't link it to Google Maps. Formatting rules like this would be hard to implement without a formatting function.

Instead of using a LinkButton control, we can also use a Literal control and construct the link ourselves within the formatting function. This way we have more control over the link's target and other aspects. 

<asp:TemplateField HeaderText="POI Name">
    <asp:Literal ID="Literal1" runat="server" Text=
      "<%# GetGoogleMapsLink(Eval(&quot;POIName&quot;),
      Eval(&quot;Longitude&quot;)) %>">

The corresponding formatting function GetGoogleMapsLink looks like:

protected string GetGoogleMapsLink(object poiName, object lat, object lon)
    string poi = (Convert.IsDBNull(poiName)) ? "Unknown POI" : (string)poiName;
    if (Convert.IsDBNull(lat) || Convert.IsDBNull(lon))
        return poi;
        return string.Format(
            "<a href=\"#\" title=\"map it\" onclick=\"
            '{0},{1}&z=15', 'GM')\">
            {2}</a>", lat, lon, poi);

The formatting function creates and returns a link that opens Google Maps in a separate browser window. It also handles the possibility of a null POIName field. If we compare the server generated pages from the above two ways (in a browser, right click the page and select View Source), we will see that the result of the second way is much more readable and less clustered.

Now let's see how we do about the combined Address field. The traditional way is to have a TemplateField with several Label controls, one for each address element, such as:

<asp:TemplateField HeaderText="Address">
    <asp:Label ID="Label1" runat="server" Text='<%# Bind("Address") %>'></asp:Label>,
    <asp:Label ID="Label2" runat="server" Text='<%# Bind("City") %>'></asp:Label>,
    <asp:Label ID="Label3" runat="server" Text='<%# Bind("County") %>'></asp:Label>,
    <asp:Label ID="Label4" runat="server" Text='<%# Bind("State") %>'></asp:Label>,
    <asp:Label ID="Label5" runat="server" Text='<%# Bind("Zip") %>'></asp:Label>,
    <asp:Label ID="Label6" runat="server" Text='<%# Bind("Country") %>'></asp:Label>

Notice that we use commas to separate address elements from each other. This is all fine until we want a little bit formatting logic - we want to trim off any excess commas at both ends of the combined address string due to possible missing address elements. However, if an address element in the middle is missing, we'll still keep the extra comma. To do this we use a single Label control and bind its Text attribute to a formatting function that takes all the address fields as input parameters:

<asp:TemplateField HeaderText="Address">
    <asp:Label ID="Label1" runat="server" Text="<%# FormatAddress(
      Eval(&quot;Country&quot;)) %>">

where, the formatting function FormatAddress is:

protected string FormatAddress(object address, object city, object county,
    object state, object zip, object country)
    string addr = string.Format("{0},{1},{2},{3},{4},{5}", address,
        city, county, state, zip, country);
    return addr.Trim(",".ToCharArray());

An improvement over the above use of a formatting function with a TemplateField is that we can pass the entire data row to the formatting function in stead of individual data fields, especially when more than one or two data fields are involved. For instance, instead of passing 6 data fields in the above case, we can pass the current data row to FormatAddress:

<asp:TemplateField HeaderText="Address">
    <asp:Label ID="Label1" runat="server"
      Text="<%# FormatAddress(((System.Data.DataRowView)Container.DataItem).Row) %>">

Here, Container.DataItem returns a DataRowView object corresponding to the DataSource record bound to the GridViewRow. Its Row property returns a DataRow object. The new formatting function FormatAddress now looks like:

protected string FormatAddress(DataRow dr)
    string addr = string.Format("{0},{1},{2},{3},{4},{5}",
        dr["Address"], dr["City"], dr["County"], dr["State"], dr["Zip"], dr["Country"]);
    return addr.Trim(",".ToCharArray());

This is obviously a much cleaner way than passing multiple data fields. The following screenshot shows the GridView with search result of some airports and airport terminals near Los Angeles.

In conclusion, a formatting function is a great way to extent the power of TemplateField. It allows developers to implement complex formatting rules that usually involve multiple data fields and their interrelationships.


A seasoned computer professional. A tofu culture evangelist...
more >>

Tag Cloud


<<  April 2017  >>

View posts in large calendar
Copyright © 2008-2011 Gong Liu. All rights reserved. | credits | contact me
The content on this site represents my own personal opinions, and does not reflect those of my employer in any way.