Extending the GridView Control


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:

  • 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 validated field.

Creating a Long Text Field

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, the LongTextField displays the text in a scrolling <div> tag. In edit display mode, the text appears in a multi-line TextBox control (see Figure 11.23).

Figure 11.23. Displaying a long text field.


To create a custom field, we'll inherit a new class from the base BoundField control. The custom LongTextField is contained in Listing 11.31.

Listing 11.31. LongTextField.vb

[View full width]

Imports System Imports System.Web.UI Imports System.Web.UI.WebControls Imports System.Web.UI.HtmlControls Namespace myControls     ''' <summary>     ''' Enables you to display a long text field     ''' </summary>     Public Class LongTextField         Inherits BoundField         Private _width As Unit = New Unit("250px")         Private _height As Unit = New Unit("60px")         ''' <summary>         ''' The width of the field         ''' </summary>         Public Property Width() As Unit             Get                 Return _width             End Get             Set(ByVal Value As Unit)                 _width = Value             End Set         End Property         ''' <summary>         ''' The height of the field         ''' </summary>         Public Property Height() As Unit             Get                 Return _height             End Get             Set(ByVal Value As Unit)                 _height = Value             End Set         End Property         ''' <summary>         ''' Builds the contents of the field         ''' </summary>         Protected Overrides Sub InitializeDataCell(ByVal cell As DataControlFieldCell,  ByVal rowState As DataControlRowState)             ' If not editing, show in scrolling div             If (rowState And DataControlRowState.Edit) = 0 Then                 Dim div As HtmlGenericControl = New HtmlGenericControl("div")                 div.Attributes("class") = "longTextField"                 div.Style(HtmlTextWriterStyle.Width) = _width.ToString()                 div.Style(HtmlTextWriterStyle.Height) = _height.ToString()                 div.Style(HtmlTextWriterStyle.Overflow) = "auto"                 AddHandler div.DataBinding, AddressOf div_DataBinding                 cell.Controls.Add(div)             Else                 Dim txtEdit As TextBox = New TextBox()                 txtEdit.TextMode = TextBoxMode.MultiLine                 txtEdit.Width = _width                 txtEdit.Height = _height                 AddHandler txtEdit.DataBinding, AddressOf txtEdit_DataBinding                 cell.Controls.Add(txtEdit)             End If         End Sub         ''' <summary>         ''' Called when databound in display mode         ''' </summary>         Private Sub div_DataBinding(ByVal s As Object, ByVal e As EventArgs)             Dim div As HtmlGenericControl = CType(s, HtmlGenericControl)             ' Get the field value             Dim value As Object = Me.GetValue(div.NamingContainer)             ' Assign the formatted value             div.InnerText = Me.FormatDataValue(value, Me.HtmlEncode)         End Sub         ''' <summary>         ''' Called when databound in edit mode         ''' </summary>         Private Sub txtEdit_DataBinding(ByVal s As Object, ByVal e As EventArgs)             Dim txtEdit As TextBox = CType(s, TextBox)             ' Get the field value             Dim value As Object = Me.GetValue(txtEdit.NamingContainer)             ' Assign the formatted value             txtEdit.Text = Me.FormatDataValue(value, Me.HtmlEncode)         End Sub     End Class  End Namespace 

In Listing 11.31, the InitializeDataCell() method is overridden. This method is responsible for creating all the controls that the custom field contains.

First, a check is made to determine whether the field is being rendered when the row is selected for editing. Notice that 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, the RowState can be both Alternate and Edit).

When the row is not in edit mode, a <div> tag is created to contain the text. An HtmlGenericControl represents the <div> tag. When the 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 multi-line TextBox control is created. When the 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 the LongTextField with the page in Listing 11.32. This page uses the LongTextField to display the value of the Movie Description column.

Listing 11.32. ShowLongTextField.aspx

<%@ Page Language="VB" %> <%@ Register TagPrefix="custom" Namespace="myControls" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head  runat="server">     <style type="text/css">         .grid td, .grid th         {             padding:5px;         }     </style>     <title>Show LongTextField</title> </head> <body>     <form  runat="server">     <div>     <asp:GridView                  Css         DataSource         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                  ConnectionString="<%$ ConnectionStrings:Movies %>"         SelectCommand="SELECT Id, Title, Director, Description             FROM Movies"         UpdateCommand="UPDATE Movies SET             Title=@Title,Director=@Director,Description=@Description             WHERE Id=@Id"         Runat="server" />     </div>     </form> </body> </html> 

Creating a Delete Button Field

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

Figure 11.24. Displaying a confirmation dialog box.


The DeleteButtonField inherits from the ButtonField class. The code for the custom field is contained in Listing 11.33.

Listing 11.33. DeleteButtonField.vb

[View full width]

Imports System Imports System.Web.UI.WebControls Namespace myControls     ''' <summary>     ''' Displays a confirmation before deleting a record     ''' </summary>     Public Class DeleteButtonField         Inherits ButtonField         Private _confirmText As String = "Delete this record?"         Public Property ConfirmText() As String             Get                 Return _confirmText             End Get             Set(ByVal Value As String)                 _confirmText = value             End Set         End Property         Public Sub New()             Me.CommandName = "Delete"             Me.Text = "Delete"         End Sub         Public Overrides Sub InitializeCell(ByVal cell As DataControlFieldCell, ByVal  cellType As DataControlCellType, ByVal rowState As DataControlRowState, ByVal rowIndex As  Integer)             MyBase.InitializeCell(cell, cellType, rowState, rowIndex)             If cellType = DataControlCellType.DataCell Then                 Dim button As WebControl = CType(cell.Controls(0), WebControl)                 button.Attributes("onclick") = String.Format("return confirm('{0}');",  _confirmText)             End If         End Sub     End Class End Namespace 

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, then 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.vb

<%@ Page Language="VB" %> <%@ Register TagPrefix="custom" Namespace="myControls" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head  runat="server">     <style type="text/css">         .grid td, .grid th         {             padding:5px;         }     </style>     <title>Show DeleteButtonField</title> </head> <body>     <form  runat="server">     <div>     <asp:GridView                  Css         DataSource         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                  ConnectionString="<%$ ConnectionStrings:Movies %>"         SelectCommand="SELECT Id, Title, Director FROM Movies"         DeleteCommand="DELETE Movies WHERE Id=@Id"         Runat="server" />     </div>     </form> </body> </html> 

Creating a Validated Field

In this final section, we create a ValidatedField custom field. This field automatically validates the data that a user enters into a GridView when editing a record. The ValidatedField uses a RequiredFieldValidator to check whether a user has entered a value, and a CompareValidator to check whether the value is the correct data type (see Figure 11.25).

Figure 11.25. Using the ValidatedField to edit a record.


The ValidatedField is a composite field. The field contains three child controlsa TextBox, RequiredFieldValidator, CompareValidatorwrapped up in a container control.

The code for the ValidatedField is contained in Listing 11.35.

Listing 11.35. ValidatedField.vb

[View full width]

Imports System Imports System.Collections.Specialized Imports System.Web.UI Imports System.Web.UI.WebControls Namespace myControls     ''' <summary>     ''' Adds RequiredFieldValidator and CompareValidator     ''' to BoundField     ''' </summary>     Public Class ValidatedField         Inherits BoundField         Private _validationDataType As ValidationDataType = ValidationDataType.String         Public Property ValidationDataType() As ValidationDataType             Get                 Return _validationDataType             End Get             Set(ByVal Value As ValidationDataType)                 _validationDataType = Value             End Set         End Property         ''' <summary>         ''' Get value from TextBox         ''' </summary>         Public Overrides Sub ExtractValuesFromCell(ByVal dictionary As IOrderedDictionary,  ByVal cell As DataControlFieldCell, ByVal rowState As DataControlRowState, ByVal  includeReadOnly As Boolean)             Dim edit As EditContainer = CType(cell.Controls(0), EditContainer)             If dictionary.Contains(DataField) Then                 dictionary(DataField) = edit.Text             Else                 dictionary.Add(DataField, edit.Text)             End If         End Sub         ''' <summary>         ''' Called when field is bound to data source         ''' </summary>         Protected Overrides Sub OnDataBindField(ByVal sender As Object, ByVal e As EventArgs)             Dim source As Control = CType(sender, Control)             ' Get the field value             Dim value As Object = Me.GetValue(source.NamingContainer)             ' If the control is a table cell, display the text             If TypeOf source Is DataControlFieldCell Then                 Dim formattedValue As String = Me.FormatDataValue(value, Me.HtmlEncode)                 If formattedValue = String.Empty Then                      formattedValue = "&nbsp;"                 End If                 CType(source, DataControlFieldCell).Text = formattedValue             End If             ' If the control is an editor, display the editor             If TypeOf source Is EditContainer Then                 Dim formattedValue As String = String.Empty                 Select Case _validationDataType                     Case ValidationDataType.Date                         Dim vdate As DateTime = CType(value, DateTime)                         formattedValue = vdate.ToShortDateString()                     Case ValidationDataType.Currency                         Dim dec As Decimal = CType(value, Decimal)                         formattedValue = dec.ToString("F")                     Case Else                         formattedValue = value.ToString()                 End Select                 CType(source, EditContainer).Text = formattedValue             End If         End Sub         ''' <summary>         ''' Build the field         ''' </summary>         Protected Overrides Sub InitializeDataCell(ByVal cell As DataControlFieldCell,  ByVal rowState As DataControlRowState)             If (rowState And DataControlRowState.Edit) = 0 Then                 AddHandler cell.DataBinding, AddressOf Me.OnDataBindField             Else                 Dim editor As EditContainer = New EditContainer(DataField,  _validationDataType)                 AddHandler editor.DataBinding, AddressOf Me.OnDataBindField                 cell.Controls.Add(editor)             End If         End Sub     End Class     ''' <summary>     ''' This control is added to the field     ''' </summary>     Public Class EditContainer         Inherits Control         Implements INamingContainer         Private _dataField As String         Private _validationDataType As ValidationDataType         Private _txtEdit As TextBox         Private _valReq As RequiredFieldValidator         Private _valCompare As CompareValidator         Public Sub New(ByVal dataField As String, ByVal validationDataType As  ValidationDataType)             _dataField = dataField             _validationDataType = validationDataType         End Sub         ''' <summary>         ''' Expose the TextBox control's Text property         ''' </summary>         Public Property Text() As String             Get                 EnsureChildControls()                 Return _txtEdit.Text             End Get             Set(ByVal Value As String)                 EnsureChildControls()                 _txtEdit.Text = Value             End Set         End Property         ''' <summary>         ''' Add TextBox, RequiredFieldValidator, and         ''' CompareValidator         ''' </summary>         Protected Overrides Sub CreateChildControls()             ' Add the textbox             _txtEdit = New TextBox()             _txtEdit.ID = "txtEdit"             Controls.Add(_txtEdit)             ' Add a RequiredFieldValidator control             _valReq = New RequiredFieldValidator()             _valReq.Display = ValidatorDisplay.Dynamic             _valReq.Text = "(required)"             _valReq.ControlToValidate = _txtEdit.ID             Controls.Add(_valReq)             ' Add a CompareValidator control             _valCompare = New CompareValidator()             _valCompare.Display = ValidatorDisplay.Dynamic             _valCompare.Operator = ValidationCompareOperator.DataTypeCheck             _valCompare.Type = _validationDataType             _valCompare.Text = "(invalid)"             _valCompare.ControlToValidate = _txtEdit.ID             Controls.Add(_valCompare)         End Sub     End Class  End Namespace 

The file in Listing 11.35 contains two classes. It contains the ValidatedField class and the EditContainer class.

The ValidatedField class derives from the BoundField class and overrides the InitializeDataCell() method. When a row is not selected for editing, the field simply displays the value of the data item associated with it. When a row is selected for editing, the field creates a new EditContainer control.

The EditContainer control contains a TextBox, RequiredFieldValidator, and CompareValidator. Notice that the EditContainer implements the INamingContainer interface. Implementing this interface prevents naming collisions when more than one instance of the ValidatedField is used in a GridView row.

The ValidatedField is used in the page in Listing 11.36. This page contains a GridView control that you can use to edit the Movies database table. The GridView control includes three ValidatedFields: one for the Title, DateReleased, and BoxOfficeTotals columns.

If you edit a column, and attempt to submit the column without entering a value, then a validation error is displayed. Furthermore, if you attempt to enter a value that is not a date for the DateReleased column or a value that is not a currency amount for the BoxOfficeTotals column, then a validation error is displayed.

Listing 11.36. ShowValidatedField.aspx

<%@ Page Language="VB" %> <%@ Register TagPrefix="custom" Namespace="myControls" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head  runat="server">     <title>Show ValidatedField</title> </head> <body>     <form  runat="server">     <div>     <asp:GridView                  DataKeyNames="Id"         DataSource         AutoGenerateEditButton="true"         AutoGenerateColumns="false"         Runat="server">         <Columns>         <custom:ValidatedField             DataField="Title"             HeaderText="Movie Title" />         <custom:ValidatedField             DataField="DateReleased"             DataFormatString="{0:D}"             HtmlEncode="false"             ValidationDataType="Date"             HeaderText="Date Released" />         <custom:ValidatedField             DataField="BoxOfficeTotals"             DataFormatString="{0:c}"             HtmlEncode="false"             ValidationDataType="Currency"             HeaderText="Box Office Totals" />         </Columns>     </asp:GridView>     <asp:SqlDataSource                  ConnectionString="<%$ ConnectionStrings:Movies %>"         SelectCommand="SELECT * FROM Movies"         UpdateCommand="UPDATE Movies SET Title=@Title,             DateReleased=@DateReleased, BoxOfficeTotals=@BoxOfficeTotals             WHERE Id=@Id"         Runat="server" />     </div>     </form> </body> </html> 




ASP. NET 2.0 Unleashed
ASP.NET 2.0 Unleashed
ISBN: 0672328232
EAN: 2147483647
Year: 2006
Pages: 276

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net