ASP.NET provides three data list controls for working with the output of a data
store query, the DataGrid, DataList and Repeater. The DataGrid, in its most
basic form, renders typical HTML table-grid output, the DataList renders one
row and one cell per record, and the Repeater is the folding metal chair of
data controls, which renders no specific output, and is fully customizable to
render in the manner most appropriate for your application. While the Repeater
seems to offer the most custom functionality, the DataGrid offers the most
built-in functionality, such as paging, column sorting and filtering. The
DataGrid may render in its basic for as a plain old table, but it also provides
functionality for full customization of the output through the use of
TemplateColumns.
In this tutorial you will learn how to customize the output of a DataGrid using
a TemplateColumn, EditCommandColumn, HyperlinkColumn, ButtonColumn and
BoundColumn.
It's Bound to be a Column
Typically when you bind data to a DataGrid, you get a basic table, one row for
each record, and one cell for each column of data. While this is great for a
lot of needs, it often does not address the specific layout you have in mind.
While a DataList or a Repeater may seem like a quick solution, it means giving
up some of the functionality that only the DataGrid offers, such as paging and
column sorting. An alternate solution is to use the DataGrid, and provide
custom layout options. These options exist in the form of different types of
data-bound columns and custom templates. To make use of these features, the
first thing to do is stop the DataGrid from automatically generating the
columns based on the data in your table. This is done with the AutoGenerateColumns
property of the DataGrid. Setting this property to
False
will stop the DataGrid from generating the columns and enable you to generate a
custom layout. Listing 1 shows how to set the
AutoGenerateColumns
property of the DataGrid.
Listing 1 - Turning AutoGenerateColumns Off
<asp:DataGrid runat=
"server"id="myDataGrid" AutoGenerateColumns="False">
</asp:DataGrid>
|
The next step is to define the layout you desire. One of the simplest ways to
control output is to work with the various data-bound column types
available with the DataGrid. Any custom column controls must be embedded
inside a
<Columns></Columns>
tag pair. I'll start by showing you the BoundColumn.
A BoundColumn is nothing more that a DataGrid column bound to a specific
data source field specified by you. To use a BoundColumn, place an
<asp:BoundColumn>
object after the
<Columns> opening tag, and before
the </Columns>
closing tag. The BoundColumn can specify the
DataField
in the source it is bound to, a
DataFormatString,
FooterText,
HeaderText, a
HeaderImageUrl
and a
SortField. Listing 2 shows a DataGrid that uses
BoundColumns to render custom output.
Listing 2 - Creating Custom Output with BoundColumns
|
Demo1.aspx
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="Demo1.aspx.vb"
Inherits="DataGridTemplates01.Demo1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>Demo1</title>
<meta name="GENERATOR" content="Microsoft Visual
Studio .NET 7.1">
<meta name="CODE_LANGUAGE" content="Visual Basic
.NET 7.1">
<meta name="vs_defaultClientScript"
content="JavaScript">
<meta name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body>
<form id="Form1" method="post" runat="server">
<asp:DataGrid runat="server"
id="myDataGrid" AutoGenerateColumns="False" BorderWidth="1px"
Font-Names="Verdana,Arial,sans-serif"
Font-Size="12px"
BorderColor="#404040" GridLines="Horizontal" CellPadding="4">
<AlternatingItemStyle
BackColor="#E0E0E0"></AlternatingItemStyle>
<HeaderStyle
Font-Bold="True" ForeColor="White" BackColor="Teal"></HeaderStyle>
<Columns>
<asp:BoundColumn
DataField="CustomerID" HeaderText="ID"></asp:BoundColumn>
<asp:BoundColumn
DataField="CompanyName" HeaderText="Company Name"></asp:BoundColumn>
<asp:BoundColumn
DataField="ContactName" HeaderText="Contact Name"></asp:BoundColumn>
<asp:BoundColumn
DataField="Address" HeaderText="Address"></asp:BoundColumn>
<asp:BoundColumn
DataField="City" HeaderText="City"></asp:BoundColumn>
<asp:BoundColumn
DataField="Region" HeaderText="Region"></asp:BoundColumn>
<asp:BoundColumn
DataField="PostalCode" HeaderText="Postal Code">
<HeaderStyle
Wrap="False"></HeaderStyle>
</asp:BoundColumn>
</Columns>
</asp:DataGrid>
</form>
</body>
</HTML>
Demo1.aspx.vb
Imports System.Data.SqlClient
Public Class Demo1
Inherits System.Web.UI.Page
#Region " Web Form Designer Generated Code "
'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
End Sub
Protected WithEvents myDataGrid As System.Web.UI.WebControls.DataGrid
'NOTE: The following placeholder declaration is required by the Web Form
Designer.
'Do not delete or move it.
Private designerPlaceholderDeclaration As System.Object
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
If Not Page.IsPostBack Then
BindData()
End If
End Sub
Public SubBindData()
DimconAsNewSqlConnection("server=localhost;database=Northwind;uid=sa;pwd=;")
Dim cmd As New SqlCommand("SELECT * FROM Customers", con)
Try
con.Open()
myDataGrid.DataSource = cmd.ExecuteReader()
myDataGrid.DataBind()
con.Close()
Catch ex As Exception
If (Not con Is Nothing) AndAlso (con.State =
ConnectionState.Open) Then
con.Close()
End If
End Try
End Sub
End Class
|
In Listing 2 you created an ASP.NET Web Form, as seen in Figure 1, that renders
a grid with a column for each DataTable column you need to display.
Figure 1 - The Output of a DataGrid Using BoundColumns

More Columns In a Bind
The other column controls, except the TemplateColumn and the EditCommandColumn,
work in a similar fashion. With each one you specify a
DataField
in some manner (DataTextField,
DataNavigateUrlField, etc.).
When you are using the HyperlinkColumn, which renders HTML hyperlink
text, you can specify the
DataTextField
- the text displayed on the screen, the
DataNavigateUrlField
- the URL to link to, and a
DataNavigateUrlFormatString
- a format expression to apply to the text output of the control.
Like the HyperlinkColumn, the ButtonColumn also provides a
DataTextField
property, and a
DataTextFormatString
property. It also provides a
CommandName
property to specify which server-side method to call when the button is clicked
and the form is posted. Using the
CommandName
property requires that the DataGrid's
OnItemCommand
property points to a method. The
CommandName
property is passed to that method and can be evaluated. This enables you to
have multiple ButtonColumns in one row. The ButtonColumn can render either a
LinkButton
(the default) or a
PushButton
- an HTML
<input type="button">
element. Listing 3 shows a DataGrid that has a custom layout using the
different types of data-bound columns.
Listing 3 - Creating Custom Output with the Data-Bound Columns
|
Demo2.aspx
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="Demo2.aspx.vb"
Inherits="DataGridTemplates01.Demo2"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>Demo2</title>
<meta name="GENERATOR" content="Microsoft Visual
Studio .NET 7.1">
<meta name="CODE_LANGUAGE" content="Visual Basic
.NET 7.1">
<meta name="vs_defaultClientScript"
content="JavaScript">
<meta name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body MS_POSITIONING="FlowLayout">
<form id="Form1" method="post" runat="server">
<asp:DataGrid id="myDataGrid"
runat="server" OnItemCommand="myDataGrid_CommandItem"
HeaderStyle-Font-Bold="True"
Cellpadding="4"
BorderWidth="1px" AutoGenerateColumns="False" GridLines="Horizontal"
Font-Names="Verdana,Arial,sans-serif"
Font-Size="12px"
BorderStyle="Solid">
<AlternatingItemStyle
BackColor="#EFEFEF"></AlternatingItemStyle>
<ItemStyle
Font-Size="X-Small"></ItemStyle>
<HeaderStyle
Font-Bold="True" ForeColor="White" BackColor="Teal"></HeaderStyle>
<Columns>
<asp:BoundColumn
DataField="CustomerID" HeaderText="ID"></asp:BoundColumn>
<asp:HyperLinkColumn
DataNavigateUrlField="Url" DataTextField="CompanyName" HeaderText="Comapny
Name"></asp:HyperLinkColumn>
<asp:ButtonColumn
Text="Get Details" ButtonType="PushButton"
CommandName="GetDetails"></asp:ButtonColumn>
</Columns>
</asp:DataGrid>
</form>
</body>
</HTML>
Demo2.aspx.vb
Imports System.Data.SqlClient
Imports System.Web.UI.WebControls
Public Class Demo2
Inherits System.Web.UI.Page
#Region " Web Form Designer Generated Code "
'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
End Sub
Protected WithEvents myDataGrid As
System.Web.UI.WebControls.DataGrid
'NOTE: The following placeholder declaration is required by the Web
Form Designer.
'Do not delete or move it.
Private designerPlaceholderDeclaration As System.Object
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form
Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
If Not Page.IsPostBack Then
BindData()
End If
End Sub
Public SubBindData()
DimconAsNewSqlConnection("server=localhost;database=Northwind;uid=sa;pwd=;")
Dim cmd As New SqlCommand("SELECT *, 'http://www.' +
CustomerID + '.com' As Url FROM Customers", con)
Try
con.Open()
myDataGrid.DataSource = cmd.ExecuteReader()
myDataGrid.DataBind()
con.Close()
Catch ex As Exception
If (Not con Is Nothing) AndAlso (con.State
= ConnectionState.Open) Then
con.Close()
End If
End Try
End Sub
Public Sub myDataGrid_CommandItem(ByVal Source As Object, ByVal E
As DataGridCommandEventArgs)
If E.CommandName = "GetDetails" Then
Response.Redirect("Demo3.aspx?id=" &
E.Item.Cells(0).Text)
End If
End Sub
End Class
|
In Listing 3 you retreive Customer information from the Northwind
database. Since the Northwind database does not have any URL information in it,
you faked it by creating a column named
Url, using the
CustomerID
column as a domain name. This is just for example purposes, but you can see how
a HyperlinkColumn works with this.
You also created a
myDataGrid_CommandItem()
event handler. The DataGrid's
OnItemCommand
property specifies this event handler as the method to call when an item
command is executed. Using a ButtonColumn, you specify the
CommandName "GetDetails". In the event handler
you evaluate for this
CommandName
and react based on the outcome of the evaluation. If the
CommandName
(E.CommandName) passed to the event handler is
"GetDetail"
then you redirect the request to a new Web Form,
Demo3.aspx
with a,
"id"
name/value pair in the QueryString. I'll show you how to build that page in a
few moments. Figure 1.2 shows the output of Listing 3
Figure 2 - Using the BoundColumn, HyperlinkColumn and ButtonColumn with a
DataGrid

In Figure 2 you can see that the first column, ID, is rendered as basic text.
You used a BoundColumn for this field, so text is the desired output. The
second column, Company Name, is an HTML hyperlink. The text displayed is the
CompanyName
field from the database, and the hyperlink URL is the
CustomerID
field from the database surrounded with
http://www.
and
.com. Lastly, the third column is a button that
will invoke the
myDataGrid_CommandItem
event handler, and pass
"GetDetail"
as the
CommandName.
Templates Are the Key to True Freedom
ASP.NET TemplateColumns allow you to create fully customized output
within the DataGrid. The TemplateColumn contains up to four different
templates. The four template types are:
-
HeaderTemplate
-
ItemTemplate
-
EditItemTemplate
-
FooterTemplate
The HeaderTemplate is used for displaying text, images, or bound data in
the header row for this column. The FooterTemplate is the same as the
HeaderTemplate, but for the footer row of the column. The EditItemTemplate
is an alternate display of the data in the template for use with DataGrid
editing (see Editing with the ASP.NET
DataGrid).
The ItemTemplate allows you to create a custom layout for the data you
want to display. Within the template you can create a fully custom layout. Each
record in the data source will render one iteration of the ItemTemplate. Using
the data binding syntax
<%#
Container.DataItem("[FieldName]") %>
or
<%# DataBinder.Eval(Container.DataItem, "[FieldName]",
"{0:[FormatString]}") %>
you can embed bound data from a record in the ItemTemplate.
Listing 4 shows the Web Form you redirected to in the
myDataCommand_CommandItem
event handler in Listing 3. This Web Form checks the Request.QueryString object
before creating the data source. If there is an
"id"
name/value pair in the QueryString the SQL statement is modified to select only
a single record based on the
"id"
value. If there is no
"id"
name/value pair, the
BindData()
method select all records from the Customers table in the Northwind database.
Listing 4 - Using the TemplateColumn with the DataGrid
|
Demo3.aspx
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="Demo3.aspx.vb"
Inherits="DataGridTemplates01.Demo3"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>Demo3</title>
<meta content="Microsoft Visual Studio .NET 7.1"
name="GENERATOR">
<meta content="Visual Basic .NET 7.1"
name="CODE_LANGUAGE">
<meta content="JavaScript"
name="vs_defaultClientScript">
<meta
content="http://schemas.microsoft.com/intellisense/ie5"
name="vs_targetSchema">
</HEAD>
<body MS_POSITIONING="FlowLayout">
<form id="Form1" method="post" runat="server">
<asp:datagrid id="myDataGrid"
runat="server" ItemStyle-Font-Size="x-small" HeaderStyle-Font-Bold="True"
HeaderStyle-Font-Size="x-small"
AlternatingItemStyle-BackColor="#EFEFEF" Cellpadding="4" BorderWidth="1"
AutoGenerateColumns="False"
BorderStyle="Solid" GridLines="Horizontal" BorderColor="#404040"
Font-Names="Verdana,Arial,sans-serif"
Font-Size="11px">
<AlternatingItemStyle
BackColor="#E0E0E0"></AlternatingItemStyle>
<ItemStyle
Font-Size="X-Small"></ItemStyle>
<HeaderStyle
Font-Size="X-Small" Font-Bold="True" ForeColor="White"
BackColor="Teal"></HeaderStyle>
<Columns>
<asp:TemplateColumn>
<HeaderTemplate>
<b>Company
Detail</b>
</HeaderTemplate>
<ItemTemplate>
<table
border="0" Cellpadding="4" Cellspacing="0" Width="100%" style="FONT-SIZE: 11px;
FONT-FAMILY: Verdana, Arial, sans-serif">
<tr>
<td
colspan="4">
<b>
<%#
Container.DataItem("CompanyName") %>
</b>
</td>
</tr>
<tr>
<td
width="25%" valign="top"><b>Contact:</b></td>
<td
width="25%" valign="top" nowrap>
<%#
Container.DataItem("ContactName") %>
</td>
<td
width="25%" valign="top"><b>Phone:</b></td>
<td
width="25%" valign="top" nowrap>
<%#
Container.DataItem("Phone") %>
</td>
</tr>
<tr>
<td
width="25%" valign="top"><b>Title:</b></td>
<td
width="25%" valign="top">
<%#
Container.DataItem("ContactTitle") %>
</td>
<td
width="25%" valign="top"><b>Fax:</b></td>
<td
width="25%" valign="top" nowrap>
<%#
Container.DataItem("Fax") %>
</td>
</tr>
<tr>
<td
width="25%" valign="top"><b>Address:</b></td>
<td
width="25%" valign="top" colspan="3">
<%#
Container.DataItem("Address") %>
<br>
<%#
Container.DataItem("City") %>
,
<%#
Container.DataItem("Region") %>
<%#
Container.DataItem("PostalCode") %>
<br>
<%#
Container.DataItem("Country") %>
</td>
</tr>
</table>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:datagrid></form>
</body>
</HTML>
Demo3.aspx.vb
Imports System.Data.SqlClient
Public Class Demo3
Inherits System.Web.UI.Page
#Region " Web Form Designer Generated Code "
'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
End Sub
Protected WithEvents myDataGrid As
System.Web.UI.WebControls.DataGrid
'NOTE: The following placeholder declaration is required by the Web
Form Designer.
'Do not delete or move it.
Private designerPlaceholderDeclaration As System.Object
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form
Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
If Not Page.IsPostBack Then
BindData()
End If
End Sub
Public Sub BindData()
Dim ds As New DataSet
Dim sda As SqlDataAdapter
Dim strSQL As String
If Request.QueryString.Item("id") Is Nothing Then
strSQL = "SELECT * FROM Customers"
Else
strSQL = "SELECT * FROM Customers WHERE
CustomerID = '" & _
Request.QueryString.Item("id").ToString()
& "'"
End If
sda = New SqlDataAdapter(strSQL, _
"server=localhost;database=Northwind;uid=sa;pwd=;")
sda.Fill(ds, "Customers")
myDataGrid.DataSource =
ds.Tables("Customers").DefaultView
myDataGrid.DataBind()
End Sub
End Class
|
In Listing 4 you create a Web Form that uses a customized DataGrid. The DataGrid
has a HeaderTemplate to give the column a name, and an ItemTemplate to create a
custom layout for the data. Using a TemplateColumn does not prevent you from
using BoundColumns, HyperlinkColumns, ButtonColumns or EditCommandColumns in
the DataGrid. All of the different data-bound columns may be used together, if
the situation calls for it. Figure 3 shows the output of Listing 4 without an
"id"
name/value pair passed in.
Figure 3 - Using the ItemTemplate with a DataGrid

Summary
While at first it seems that only the DataList or the Repeater controls are
adequate solutions when custom layout is needed, the fact is the DataGrid is
truly the powerhouse data control. Not only does it include paging and sorting
functionality that the other controls do not have, but it also has the
framework to enable rich customization of the output. Having learned from this
article, take a look around DotNetJunkies.com...you'll see a lot of the
DataGrid at work.