ptg
554
CHAPTER 11 Using the GridView Control
.categories h1
{
font:bold 16px Arial, Sans-Serif;
}
.movies
{
margin-left:20px;
margin-bottom:10px;
width:100%;
}
</style>
<title>Nested Master/Detail</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<asp:GridView
id=”grdMovies”
DataSourceID=”srcMovieCategories”
OnRowDataBound=”grdMovieCategories_RowDataBound”
AutoGenerateColumns=”false”
CssClass=”categories”
ShowHeader=”false”
GridLines=”none”
Runat=”server”>
<Columns>
<asp:TemplateField>
<ItemTemplate>
<h1><%# Eval(“Name”) %></h1>
<asp:GridView
id=”grdMovies”
DataSourceId=”srcMovies”
CssClass=”movies”
GridLines=”none”
Runat=”server” />
<asp:SqlDataSource
id=”srcMovies”
ConnectionString=”<%$ ConnectionStrings:Movies %>”
SelectCommand=”SELECT Title,Director FROM Movies
WHERE CategoryId=@CategoryId”
Runat=”server”>
<SelectParameters>
<asp:Parameter Name=”CategoryId” />
</SelectParameters>
From the Library of Wow! eBook
ptg
555
Extending the GridView Control
11
</asp:SqlDataSource>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:SqlDataSource
id=”srcMovieCategories”
ConnectionString=”<%$ ConnectionStrings:Movies %>”
SelectCommand=”SELECT Id,Name FROM MovieCategories”
Runat=”server” />
</div>
</form>
</body>
</html>
The grdMovieCategories_RowDataBound() method handles the RowDataBound event. This
event handler grabs the movie category ID from the current row’s DataItem property.
Next, it retrieves the SqlDataSource control contained in the grdMovieCategories
TemplateField. Finally, it assigns the movie category ID to a parameter contained in the
SqlDataSource control’s SelectParameters collection.
NOTE
You must use the FindControl() method to get the SqlDataSource control from the
TemplateField. The templates in a TemplateField each create their own naming con-
tainers to prevent naming collisions. The FindControl() method enables you to
search a naming container for a control with a matching ID.
Extending the GridView Control
Like any other control in the ASP.NET Framework, if you don’t like any aspect of the
GridView control, you always have the option of extending the control. In this section,
you learn how to extend the GridView control with custom fields.
To create a custom field, you can inherit a new class from any of the existing fields or any
of the following base classes:
From the Library of Wow! eBook
ptg
556
CHAPTER 11 Using the GridView Control
. DataControlField—The base class for all fields.
. ButtonFieldBase—The base class for all button fields, such as the ButtonField and
CommandField.
In this section, you learn how to create a long text field, a delete button field, and a vali-
dated field.
Creating a LongTextField
None of the existing GridView fields do a good job of handling large amounts of text. You
can fix this problem by creating a custom field, named the LongTextField, which you can
use to display the value of text columns regardless of the length of the text.
In normal display mode, LongTextField displays the text in a scrolling <div> tag. In edit
display mode, the text appears in a multiline TextBox control (see Figure 11.23).
FIGURE 11.23 Displaying a long text field.
To create a custom field, a new class must be inherited from the base BoundField control.
The custom LongTextField is contained in Listing 11.31.
From the Library of Wow! eBook
ptg
557
Extending the GridView Control
11
LISTING 11.31 LongTextField.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace myControls
{
/// <summary>
/// Enables you to display a long text field
/// </summary>
public class LongTextField : BoundField
{
private Unit _width = new Unit(“250px”);
private Unit _height = new Unit(“60px”);
/// <summary>
/// The Width of the field
/// </summary>
public Unit Width
{
get { return _width; }
set { _width = value; }
}
/// <summary>
/// The Height of the field
/// </summary>
public Unit Height
{
get { return _height; }
set { _height = value; }
}
/// <summary>
/// Builds the contents of the field
/// </summary>
protected override void InitializeDataCell(DataControlFieldCell cell,
DataControlRowState rowState)
{
// If not editing, show in scrolling div
if ((rowState & DataControlRowState.Edit) == 0)
{
HtmlGenericControl div = new HtmlGenericControl(“div”);
div.Attributes[“class”] = “longTextField”;
From the Library of Wow! eBook
ptg
558
CHAPTER 11 Using the GridView Control
div.Style[HtmlTextWriterStyle.Width] = _width.ToString();
div.Style[HtmlTextWriterStyle.Height] = _height.ToString();
div.Style[HtmlTextWriterStyle.Overflow] = “auto”;
div.DataBinding += new EventHandler(div_DataBinding);
cell.Controls.Add(div);
}
else
{
TextBox txtEdit = new TextBox();
txtEdit.TextMode = TextBoxMode.MultiLine;
txtEdit.Width = _width;
txtEdit.Height = _height;
txtEdit.DataBinding += new EventHandler(txtEdit_DataBinding);
cell.Controls.Add(txtEdit);
}
}
/// <summary>
/// Called when databound in display mode
/// </summary>
void div_DataBinding(object s, EventArgs e)
{
HtmlGenericControl div = (HtmlGenericControl)s;
// Get the field value
Object value = this.GetValue(div.NamingContainer);
// Assign the formatted value
div.InnerText = this.FormatDataValue(value, this.HtmlEncode);
}
/// <summary>
/// Called when databound in edit mode
/// </summary>
void txtEdit_DataBinding(object s, EventArgs e)
{
TextBox txtEdit = (TextBox)s;
// Get the field value
Object value = this.GetValue(txtEdit.NamingContainer);
// Assign the formatted value
From the Library of Wow! eBook
ptg
559
Extending the GridView Control
11
txtEdit.Text = this.FormatDataValue(value, this.HtmlEncode);
}
}
}
In Listing 11.31, the InitializeDataCell() method is overridden. This method is respon-
sible for creating all the controls that the custom field contains.
First, a check is made to determine whether the field is rendered when the row is selected
for editing. A bitwise comparison must be performed with the rowState parameter because
the rowState parameter can contain combinations of the values Alternate, Normal,
Selected, and Edit (for example, RowState can be both Alternate and Edit).
When the row is not in edit mode, a <div> tag is created to contain the text.
HtmlGenericControl represents the <div> tag. When GridView is bound to its data
source, the <div> tags get the value of its innerText property from the
div_DataBinding() method.
When the row is selected for editing, a multiline TextBox control is created. When
GridView is bound to its data source, the TextBox control’s Text property gets its value
from the txtEdit_DataBinding() method.
You can experiment with LongTextField with the page in Listing 11.32. This page uses
LongTextField to display the value of the Movie Description column.
LISTING 11.32 ShowLongTextField.aspx
<%@ Page Language=”C#” %>
<%@ Register TagPrefix=”custom” Namespace=”myControls” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.1//EN”
“
<html xmlns=” >
<head id=”Head1” runat=”server”>
<style type=”text/css”>
.grid td, .grid th
{
padding:5px;
}
</style>
<title>Show LongTextField</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<asp:GridView
From the Library of Wow! eBook
ptg
560
CHAPTER 11 Using the GridView Control
id=”grdMovies”
CssClass=”grid”
DataSourceID=”srcMovies”
DataKeyNames=”Id”
AutoGenerateColumns=”false”
AutoGenerateEditButton=”true”
Runat=”server”>
<Columns>
<asp:BoundField
DataField=”Title”
HeaderText=”Movie Title” />
<asp:BoundField
DataField=”Director”
HeaderText=”Movie Director” />
<custom:LongTextField
DataField=”Description”
Width=”300px”
Height=”60px”
HeaderText=”Movie Description” />
</Columns>
</asp:GridView>
<asp:SqlDataSource
id=”srcMovies”
ConnectionString=”<%$ ConnectionStrings:Movies %>”
SelectCommand=”SELECT Id, Title, Director, Description
FROM Movies”
UpdateCommand=”UPDATE Movies SET
Title=@Title,Director=@Director,Description=
WHERE Id=@Id”
Runat=”server” />
</div>
</form>
</body>
</html>
Creating a DeleteButtonField
I don’t like the Delete button rendered by the GridView control’s CommandField. The
problem is that it does not provide you with any warning before you delete a record. In
this section, we fix this problem by creating a Delete button that displays a client-side
confirmation dialog box (see Figure 11.24).
From the Library of Wow! eBook
ptg
561
Extending the GridView Control
11
DeleteButtonField inherits from the ButtonField class. The code for the custom field is
contained in Listing 11.33.
LISTING 11.33 DeleteButtonField.cs
using System;
using System.Web.UI.WebControls;
namespace myControls
{
/// <summary>
/// Displays a confirmation before deleting a record
/// </summary>
public class DeleteButtonField : ButtonField
{
private string _confirmText = “Delete this record?”;
public string ConfirmText
{
get { return _confirmText; }
set { _confirmText = value; }
}
FIGURE 11.24 Displaying a confirmation dialog box.
From the Library of Wow! eBook
ptg
562
CHAPTER 11 Using the GridView Control
public DeleteButtonField()
{
this.CommandName = “Delete”;
this.Text = “Delete”;
}
public override void InitializeCell(DataControlFieldCell cell,
DataControlCellType cellType, DataControlRowState rowState, int rowIndex)
{
base.InitializeCell(cell, cellType, rowState, rowIndex);
if (cellType == DataControlCellType.DataCell)
{
WebControl button = (WebControl)cell.Controls[0];
button.Attributes[“onclick”] = String.Format(“return
➥confirm(‘{0}’);”, _confirmText);
}
}
}
}
Most of the work in Listing 11.33 is handled by the base ButtonField class. The
InitializeCell() method is overridden so that the button can be grabbed. The button is
added to the cell by the base ButtonField’s InitializeCell() method.
To create the confirmation dialog box, an onclick attribute is added to the button. If the
JavaScript confirm statement returns false, the button click is canceled.
You can test the DeleteButtonField with the page in Listing 11.34. This page enables you
to delete records from the Movies database table.
LISTING 11.34 ShowDeleteButtonField.aspx
<%@ Page Language=”C#” %>
<%@ Register TagPrefix=”custom” Namespace=”myControls” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.1//EN”
“
<html xmlns=” >
<head id=”Head1” runat=”server”>
<style type=”text/css”>
.grid td, .grid th
{
padding:5px;
}
</style>
From the Library of Wow! eBook
ptg
563
Extending the GridView Control
11
<title>Show DeleteButtonField</title>
</head>
<body>
<form id=”form1” runat=”server”>
<div>
<asp:GridView
id=”grdMovies”
CssClass=”grid”
DataSourceID=”srcMovies”
DataKeyNames=”Id”
AutoGenerateColumns=”false”
Runat=”server”>
<Columns>
<custom:DeleteButtonField
ConfirmText=”Are you sure that you want to delete this record?” />
<asp:BoundField
DataField=”Title”
HeaderText=”Movie Title” />
<asp:BoundField
DataField=”Director”
HeaderText=”Movie Director” />
</Columns>
</asp:GridView>
<asp:SqlDataSource
id=”srcMovies”
ConnectionString=”<%$ ConnectionStrings:Movies %>”
SelectCommand=”SELECT Id, Title, Director FROM Movies”
DeleteCommand=”DELETE Movies WHERE Id=@Id”
Runat=”server” />
</div>
</form>
</body>
</html>
Creating a ValidatedField
In this final section, we create a ValidatedField custom field, which automatically vali-
dates the data that a user enters into GridView when editing a record. ValidatedField
uses RequiredFieldValidator to check whether a user has entered a value, and
CompareValidator to check whether the value is the correct data type (see Figure 11.25).
From the Library of Wow! eBook