Adding Data Modification Support to a Sortable and Pageable DataGrid

Now that we've seen how to meld both the sorting and paging features inherent in the DataGrid control into a single control, it's time to turn our attention to how to enable the modification of the data in such a DataGrid. In Chapter 9, we saw how to use the DataGrid's built-in editing features, which we'll now add to a pageable, sortable DataGrid. We'll also examine how to provide delete functionality. This all-in-one DataGrid, which allows for updating, deleting, modifying, sorting, and paging through data, serves quite nicely as an administration interface for a data-driven Web site.

We'll look at adding editing and deleting support to our DataGrid one feature at a time, starting with adding an editing interface. In Chapter 9, we thoroughly examined the DataGrid's editing features. Furthermore, if you'll recall back to Chapter 4, "Adding Buttons and HyperLinks to the DataGrid Web Control," we saw how to add a Delete button to a DataGrid. (Specifically, we looked at the example of a DataGrid being used to display a shopping cart that includes Remove and Details buttons for every item in the DataGrid.)

Because we've already seen examples of editing and deleting from a DataGrid, we won't spend too much time examining the details of providing such features to a pageable, sortable DataGrid. Rather, we'll focus on what issues arise when attempting to add such features to a DataGrid that already supports sorting and paging.

NOTE

Because the DataGrid was designed for displaying, editing, sorting, and paging records, we will not spend time discussing how to use the DataGrid to add records, although there are clever tricks you can employ to use the DataGrid interface for adding data. For more information on these techniques, be sure to read the "Quickly Adding a New Row in a DataGrid" article, referenced in the "On the Web" section at the end of this chapter.

Typically, if you want to allow the insertion of data into the Comment table, you would provide a separate ASP.NET Web page that simply displays a Web form with the needed input fields, and, once filled out and submitted, inserts the information into the database. Although this can be done on the same page as the DataGrid, it can lead to complications if validation controls are used both for the editing interface and for the data-inserting section on the page. Furthermore, placing both data display and data insertion features on one page leads to a cluttered interface that your users might find confusing or difficult to navigate.


Adding Editing Support to a Sortable, Pageable DataGrid

Recall from Chapter 9 that to add editing support for a DataGrid, we need to perform three steps:

  1. Add an EditCommandColumn to the DataGrid. (The EditCommandColumn is rendered into an Edit button for each DataGrid row, or an Update and Cancel button for the row that is currently being edited. )

  2. For any columns that require a custom editing interface, use a TemplateColumn with an EditItemTemplate to provide the needed editing interface.

  3. Provide event handlers for the DataGrid's EditCommand, UpdateCommand, and CancelCommand events, which fire when the user clicks the Edit, Update, and Cancel buttons, respectively.

What changes to these steps are needed to provide editing capabilities to a DataGrid that already supports sorting and paging?

The DataGrid determines what row to render in edit mode based on the value of the EditItemIndex property. In the event handler for the EditCommand, you must set this property to the index of the row whose Edit button was clicked, and then rebind the DataGrid. With the CancelCommand event, you must reset the DataGrid's EditItemIndex property to 1 and rebind the DataGrid. Finally, with the UpdateCommand event, you must update the database with new values the user has entered and then reset the DataGrid's EditItemIndex property to 1 and rebind the DataGrid.

The rebinding of the DataGrid in all three event handlers requires a call to the BindData() subroutine, but the BindData() subroutine has been updated to accept an string input parameter, sortExpression . One such change that must be made, as was done in Listing 10.2, is that whenever the EditCommand, UpdateCommand, or CancelCommand event handler needs to call BindData(sortExpression ), it will have to pass in the value of the SortExpr ViewState variable (ViewState("SortExpr")).

Another consideration that must be kept in mind when a DataGrid that already supports paging and sorting has editing support added is the following: Imagine that a user clicks the Edit button for a particular row in the DataGrid. As we know, the ASP.NET page will be posted back and the DataGrid will be redrawn with the particular row whose Edit button was clicked being displayed in its edit mode. Imagine at this point that the user clicks one of the sorting hyperlinks, or one of the Next/Previous hyperlinks in the paging interface. What will happen?

As you already know, the ASP.NET Web page will be posted back and the DataGrid's SortCommand event will fire (assuming the user clicked one of the sorting hyperlinks). The event handler for the SortCommand event, dgComments_Sorting, as defined in Listing 10.2, line 54, will reset the ViewState("SortExpr") variable to the new SortExpression, reset the DataGrid's CurrentPageIndex property to 0, and then rebind the DataGrid. This will result in the DataGrid being sorted by the specified column, with the first page of data showing. However, recall that prior to sorting, the user clicked the Edit button for a row, which had the effect of setting the DataGrid's EditItemIndex property to that row's index. This means that if we don't reset the DataGrid's EditItemIndex property when the first page of the new sorted data is displayed, one of the rows will be rendered as if the user had clicked the Edit button! Therefore, it is vital that both the dgComments_Sorting and the dgComments_Paging event handlers reset the DataGrid's EditItemIndex property to 1.

To summarize, the only two changes we need to make to incorporate editing support into a pageable/sortable DataGrid are to update the call to the BindData(sortExpression ) subroutine in the EditCommand, UpdateCommand, and CancelCommand event handlers, and update the dgComments_Sorting and dgComments_Paging event handlers to reset the DataGrid's EditItemIndex property to 1.

Listing 10.3 contains an updated version of Listing 10.2, which includes editing support. Note that all three columns in the DataGrid employ a customized editing interface. The Name column uses a simple TextBox; the Comment column uses a multiline TextBox as we saw in Chapter 9, Listing 9.4; and the Date Added column uses a Calendar Web control, as we saw in Chapter 9, Listing 9.5. Additionally, the Name and Comment columns use a RequiredFieldValidator validation control, as was shown in Chapter 9, Listing 9.9.

Listing 10.3 The Sortable/Pageable DataGrid Is Now Also Editable

[View full width]

   1: <%@ import Namespace="System.Data" %>    2: <%@ import Namespace="System.Data.SqlClient" %>    3: <script runat="server" language="VB">    4: '... The Page_Load event handler and the BindData(sortExpression)    5:   '... and ShowPageInformation() subroutine has been omitted for brevity    6:   '... Refer back to Listing 10.2 for details ...    7:    8:     Sub dgComments_Paging(sender As Object, e As DataGridPageChangedEventArgs)    9:       'Turn off editing   10:       dgComments.EditItemIndex = -1   11:   12:       dgComments.CurrentPageIndex = e.NewPageIndex   13:       BindData(ViewState("SortExpr"))   14:     End Sub   15:   16:   17:     Sub dgComments_Sorting(sender as Object, e as DataGridSortCommandEventArgs)   18:       'Set the sortExpr ViewState variable accordingly   19:       ViewState("SortExpr") = e.SortExpression   20:   21:       'Reset the data to show the FIRST page of data   22:       dgComments.CurrentPageIndex = 0   23:   24:       'Turn off editing   25:       dgComments.EditItemIndex = -1   26:   27:       'Bind the data!   28:       BindData(ViewState("SortExpr"))   29:     End Sub   30:   31:   32:     Sub dgComments_EditRow(sender As Object, e As DataGridCommandEventArgs)   33:       dgComments.EditItemIndex = e.Item.ItemIndex   34:       BindData(ViewState("SortExpr"))   35:     End Sub   36:   37:     Sub dgComments_UpdateRow(sender As Object, e As DataGridCommandEventArgs)   38:       'Make sure the Page is Valid    39:       If Not Page.Isvalid Then Exit Sub   40:   41:       'Get information from columns...   42:       Dim nameTextBox as TextBox = e.Item.Cells(1).FindControl("txtName")   43:       Dim commentTextBox as TextBox = e.Item.Cells(2). FindControl("txtComment")   44:       Dim dateAdded as Calendar = e.Item.Cells(3).FindControl("calDate")   45:   46:       Dim iCommentID as Integer = dgComments.DataKeys(e.Item.ItemIndex)   47:   48:   49:       'Update the database...   50:       Dim strSQL as String   51:       strSQL = "UPDATE Comments SET Name = @NameParam, DateAdded = @DateAddedParam,  graphics/ccc.gif" & _   52:                "Comment = @CommentParam WHERE CommentID = @CommentIDParam"   53:   54:       Const strConnString as String = "server=localhost;uid=sa;pwd=; database=pubs"   55:       Dim objConn as New SqlConnection(strConnString)   56:   57:       Dim objCmd as New SqlCommand(strSQL, objConn)   58:   59:       Dim nameParam as New SqlParameter("@NameParam", SqlDbType.VarChar, 50)   60:       Dim commentParam as New SqlParameter("@CommentParam", SqlDbType. VarChar, 255)   61:       Dim dateAddedParam as New SqlParameter("@DateAddedParam", SqlDbType.DateTime)   62:       Dim commentIDParam as New SqlParameter("@CommentIDParam", SqlDbType.Int, 4)   63:   64:       nameParam.Value = nameTextBox.Text   65:       objCmd.Parameters.Add(nameParam)   66:   67:       commentParam.Value = commentTextBox.Text   68:       objCmd.Parameters.Add(commentParam)   69:   70:       dateAddedParam.Value = dateAdded.SelectedDate   71:       objCmd.Parameters.Add(dateAddedParam)   72:   73:       commentIDParam.Value = iCommentID    74:       objCmd.Parameters.Add(commentIDParam)   75:   76:       'Issue the SQL command   77:       objConn.Open()   78:       objCmd.ExecuteNonQuery()   79:       objConn.Close()   80:   81:       dgComments.EditItemIndex = -1   82:       BindData(ViewState("SortExpr"))   83:     End Sub   84:   85:     Sub dgComments_CancelRow(sender As Object, e As DataGridCommandEventArgs)   86:       dgComments.EditItemIndex = -1   87:       BindData(ViewState("SortExpr"))   88:     End Sub   89: </script>   90: <form runat="server">   91:   <asp:DataGrid runat="server"    92:       Font-Name="Verdana" Font-Size="9pt" CellPadding="5"   93:       AlternatingItemStyle-BackColor="#dddddd"   94:       AutoGenerateColumns="False" Width="75%"   95:       PageSize="10" AllowPaging="True"   96:       OnPageIndexChanged="dgComments_Paging"   97:       AllowSorting="True" OnSortCommand="dgComments_Sorting"   98:       OnEditCommand="dgComments_EditRow"   99:       OnUpdateCommand="dgComments_UpdateRow"  100:       OnCancelCommand="dgComments_CancelRow"  101:       DataKeyField="CommentID">  102:  103:     <HeaderStyle BackColor="Navy" ForeColor="White" Font-Size="13pt"  104:               Font-Bold="True" HorizontalAlign="Center" />  105:  106:     <PagerStyle BackColor="Navy" ForeColor="White" Font-Size="8pt"  107:              Font-Bold="True" HorizontalAlign="Right"  108:              NextPageText="Next >" PrevPageText="< Prev" />  109:  110:     <Columns>  111:       <asp:EditCommandColumn EditText="Edit" UpdateText="Update"  112:            CancelText="Cancel" ButtonType="LinkButton" />  113:       <asp:TemplateColumn HeaderText="Name" SortExpression="Name">  114:         <ItemTemplate>  115:           <%# DataBinder.Eval(Container.DataItem, "Name") %>   116:         </ItemTemplate>  117:         <EditItemTemplate>  118:           <asp:TextBox runat="server"  Columns="15"  119:               MaxLength="50" Font-Name="Verdana" Font-Size="9pt"  120:               Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>' />  121:           <asp:RequiredFieldValidator runat="server"  122:               ControlToValidate="txtName" Display="Dynamic"  123:               ErrorMessage="<br />You must provide a Name." />  124:         </EditItemTemplate>  125:       </asp:TemplateColumn>  126:       <asp:TemplateColumn HeaderText="Comment" SortExpression="Comment">  127:         <ItemTemplate>  128:           <%# DataBinder.Eval(Container.DataItem, "Comment") %>  129:         </ItemTemplate>  130:         <EditItemTemplate>  131:           <asp:TextBox runat="server"  Width="95%"  132:               MaxLength="255" Font-Name="Verdana" Font-Size="9pt"  133:               TextMode="MultiLine" Rows="5"  134:               Text='<%# DataBinder.Eval(Container.DataItem, "Comment") %>' />  135:           <asp:RequiredFieldValidator runat="server"  136:               ControlToValidate="txtComment" Display="Dynamic"  137:               ErrorMessage="<br />You must provide a Comment." />  138:         </EditItemTemplate>  139:       </asp:TemplateColumn>  140:       <asp:TemplateColumn HeaderText="Date Added" SortExpression="DateAdded"  141:              ItemStyle-HorizontalAlign="Center">  142:         <ItemTemplate>  143:           <%# DataBinder.Eval(Container.DataItem, "DateAdded", "{0:d}") %>  144:         </ItemTemplate>  145:         <EditItemTemplate>  146:           <asp:Calendar  runat="server"  147:                 SelectedDate='<%# Convert.ToDateTime(DataBinder.Eval (Container. graphics/ccc.gifDataItem, "DateAdded")) %>'  148:                 VisibleDate='<%# Convert.ToDateTime(DataBinder.Eval (Container. graphics/ccc.gifDataItem, "DateAdded")) %>' />  149:         </EditItemTemplate>  150:       </asp:TemplateColumn>  151:     </Columns>  152:   </asp:DataGrid>  153:   <asp:label  runat="server" Font-Name="Verdana"  154:      Font-Size="9pt" Font-Italic="True" Width="75%" HorizontalAlign="Right" />  155: </form> 

As with Listing 10.2, Listing 10.3 at first appears quite formidable; however, the vast majority of the code present in Listing 10.3 has been examined thoroughly in previous chapters. The DataGrid declaration in Listing 10.3 has undergone some major work from its incarnation in Listing 10.2. Specifically, an EditCommandColumn (lines 111 and 112) has been added, and all the BoundColumns from Listing 10.2 have been converted to TemplateColumns in Listing 10.3. The reason Listing 10.3 uses TemplateColumns is because we want to provide a custom editing interface for each column.

The customized editing interfaces for each column can be found in their EditItemTemplate sections. The Name column uses a standard TextBox for its editing interface (lines 118 120), with a RequiredFieldValidator included to ensure that the user supplies a value for the Name column when editing (lines 121 123). The Comment column uses a multiline TextBox for its customized editing interface (lines 131 134) and, like the Name column, includes a RequiredFieldValidator (lines 135 137). Finally, the Date Added column's editing interface uses a Calendar Web control (lines 146 148).

In addition to providing an EditCommandColumn and editing interfaces for the editable columns, we must also wire up the DataGrid's EditCommand, UpdateCommand, and CancelCommand to appropriate event handlers. This is done on lines 98 through 100. In Chapter 9, when we first examined enabling editing support for a DataGrid, we saw that these three event handlers all ended up calling the BindData() method at some point. When using these event handlers in a DataGrid that supports paging, we must use an alternative version of BindData(), one that takes an input parameter specifying the DataSource field to sort on. Therefore, the BindData() call in these three event handlers has been replaced by a call to BindData(ViewState("SortExpr")) (see lines 34, 82, and 87), where ViewState("SortExpr") is a ViewState variable that persists what DataGrid column the results are sorted by across postbacks.

The dgComments_Sorting and dgComments_Paging event handlers from Listing 10.2 must also be updated to enable for editing support. Specifically, these two event handlers must make certain that when they are called, the DataGrid is taken out of edit mode. This is accomplished by resetting the DataGrid's EditItemIndex property to 1 (see lines 10 and 25). By setting EditItemIndex to 1, these event handlers ensure that when a user has the DataGrid in edit mode, the DataGrid gracefully exits edit mode if either a sorting hyperlink or Next/Previous paging hyperlink is clicked.

The remainder of the code in Listing 10.3 is code we have seen in previous examples in Chapter 9. Figure 10.4 contains a screenshot of Listing 10.3 when viewed through a browser. Specifically, it's a screenshot of the DataGrid after the user has opted to edit a particular row.

Figure 10.4. The user can edit the pageable/sortable DataGrid.

graphics/10fig04.gif

Providing Support to Delete Records

The DataGrid we've been working on throughout this chapter displays the contents of the Comments database table, which represents an online discussion in a guestbook or chatroom-type application. This DataGrid would be a useful tool for a site administrator, allowing all the comments to be read, sorted, edited, or selected based on the posting date or the poster. An additional feature that would be nice to include would be enabling the system administrator to delete records from the Comment table if the comment is spam or contains profanity.

To enable the deleting of data, we need to provide a Delete button in our DataGrid. In Chapter 4, we saw how to add buttons to the DataGrid through the ButtonColumn. In Chapter 5, "Adding Command Buttons to the Data Web Controls," we saw that if we add a command button to the DataGrid with a CommandName of Delete, whenever this command button is clicked, the DataGrid will fire its DeleteCommand event. These two approaches will be used to implement the deletion of data through the DataGrid. Namely, we'll use a ButtonColumn to create a command button column in the DataGrid, setting the ButtonColumn's CommandName property to "Delete". Then we'll provide an event handler for the DataGrid's DeleteCommand event; in this event handler, we'll need to determine the CommentID of the row whose Delete button was clicked, and issue a SQL statement that effectively deletes this record. The code for adding a Delete button can be seen in Listing 10.4.

Listing 10.4 With a Delete Button, an Administrator Can Delete Database Data Via the DataGrid
  1: <%@ import Namespace="System.Data" %>   2: <%@ import Namespace="System.Data.SqlClient" %>   3: <script runat="server" language="VB">   4: ' ... All of the subroutines and event handlers from   5: ' ... Listing 10.3 have been omitted, since they remain   6: ' ... unchanged here in Listing 10.4.   7:   8:     Sub dgComments_DeleteRow(sender As Object, e As DataGridCommandEventArgs)   9:       'Turn off editing  10:       dgComments.EditItemIndex = -1  11:  12:       Dim iCommentID as Integer  13:       iCommentID = dgComments.DataKeys(e.Item.ItemIndex)  14:  15:       'Update the database...  16:       Dim strSQL as String  17:       strSQL = "DELETE FROM Comments WHERE CommentID = @CommentIDParam"  18:  19:       Const strConnString as String = "server=localhost;uid=sa; pwd=;database=pubs"  20:       Dim objConn as New SqlConnection(strConnString)  21:  22:       Dim objCmd as New SqlCommand(strSQL, objConn)  23:  24:       Dim commentIDParam as New SqlParameter("@CommentIDParam", SqlDbType.Int, 4)  25:       commentIDParam.Value = iCommentID  26:       objCmd.Parameters.Add(commentIDParam)  27:  28:       'Issue the SQL command  29:       objConn.Open()  30:       objCmd.ExecuteNonQuery()  31:       objConn.Close()  32:  33:       BindData(ViewState("SortExpr"))  34:     End Sub  35: </script>  36: <form runat="server">  37:   <asp:DataGrid runat="server"   38:       Font-Name="Verdana" Font-Size="9pt" CellPadding="5"   39:       AlternatingItemStyle-BackColor="#dddddd"  40:       AutoGenerateColumns="False" Width="75%"  41:       PageSize="10" AllowPaging="True"  42:       OnPageIndexChanged="dgComments_Paging"  43:       AllowSorting="True" OnSortCommand="dgComments_Sorting"  44:       OnEditCommand="dgComments_EditRow"  45:       OnUpdateCommand="dgComments_UpdateRow"  46:       OnCancelCommand="dgComments_CancelRow"  47:       DataKeyField="CommentID"  48:       OnDeleteCommand="dgComments_DeleteRow">  49:  50:     <HeaderStyle BackColor="Navy" ForeColor="White" Font-Size="13pt"  51:               Font-Bold="True" HorizontalAlign="Center" />  52:  53:     <PagerStyle BackColor="Navy" ForeColor="White" Font-Size="8pt"  54:              Font-Bold="True" HorizontalAlign="Right"  55:              NextPageText="Next >" PrevPageText="< Prev" />  56:  57:     <Columns>  58:       <asp:EditCommandColumn EditText="Edit" UpdateText="Update"  59:            CancelText="Cancel" ButtonType="LinkButton" />  60:       <asp:ButtonColumn Text="Delete" ButtonType="LinkButton"  61:            CommandName="Delete" />  62:  63:       '... The TemplateColumn declarations for the Name, Comments, and  64:       '... Date Added columns have been omitted for brevity.  65:       '... Refer back to Listing 10.3  66:  67:     </Columns>  68:   </asp:DataGrid>  69:   <asp:label  runat="server" Font-Name="Verdana"  70:      Font-Size="9pt" Font-Italic="True" Width="75%" HorizontalAlign="Right" />  71: </form> 

Listing 10.4 contains an addition to the DataGrid declaration, as well as a new event handler to the code section. The DataGrid declaration has been updated to contain a ButtonColumn that displays a Delete button (lines 60 and 61). Because this ButtonColumn's CommandName property is set to "Delete", when the Delete button is clicked, the DataGrid's DeleteCommand event handler will fire. On line 48, we wire up this event to the dgComments_DeleteRow event handler.

NOTE

Recall from Chapters 4 and 5 that every time a command button inside a DataGrid is clicked, the DataGrid's ItemCommand event fires. By giving the command button the special CommandName value "Delete", the DataGrid's DeleteCommand event fires as well. Note that instead of using a CommandName value "Delete" and the DeleteCommand event, we could have just as easily given the command button an arbitrary CommandName value and provided an event handler for the ItemCommand event.


The dgComments_DeleteRow event handler (lines 8 34) starts like the paging and sorting event handlers: it resets the DataGrid's EditItemIndex to 1 (line 10). Next, it determines the value of the CommentID field for the row whose Delete button was clicked (line 13) and then issues a parameterized SQL statement that deletes the specified record (lines 16 through 31). Finally, the BindData(sortExpression ) subroutine is called on line 33. This is needed because the DataGrid's underlying data has changed, and we need to rebind the contents of the Comment table to the DataGrid.

Figure 10.5 contains a screenshot of the code in Listing 10.4. Note that each DataGrid row contains a Delete button. When this button is clicked, the ASP.NET Web page is posted back and the DataGrid's DeleteCommand event fires, causing the dgComments_DeleteRow event handler to execute. This deletes the specified record from the Comments database table, and then rebinds the DataGrid based on the proper sort criteria.

Figure 10.5. A system administrator can delete a database record through the DataGrid interface.

graphics/10fig05.gif

Using Client-Side Script to Ensure That the User Wants to Delete the Selected Record

Although the code in Listing 10.4 will delete a selected record, its usability leaves a bit to be desired. A common feature that is missing is a way for the user to confirm that she wants to delete a record. As soon as the user clicks the Delete button, the record is gone forever should a user accidentally click the mouse button while it's hovering over a DataGrid row's Delete button, the record will be deleted. As this all might take place in a split second, the user might not realize what has just happened.

Rather than allowing a record to be deleted so nonchalantly, let's modify our code from Listing 10.4 to include some client-side script that will require the user to acknowledge that she does, in fact, want to delete the specified record. Specifically, we'll modify the code such that when the user clicks the Delete button, a JavaScript confirm dialog box will appear asking the user whether she wants to delete the record. This dialog box will have two buttons: OK and Cancel. The record will only be deleted if the user clicks the OK button.

To provide such functionality, we need to be able to alter the HTML output of the DataGrid's Delete button such that the Delete button has a client-side onclick event that runs the following client-side JavaScript code when fired:

 return confirm("Are you sure you want to delete this record?"); 

Specifically, we'd like our Delete button's HTML to look like this:

 <a href="JavaScript code to do the postback"     onclick="return confirm('Are you sure you want to delete this record?')">    Delete  </a> 

This code will provide the desired effect, causing a modal client-side dialog box to appear when the user clicks the Delete button. Note that the href attribute of the a tag will contain some JavaScript code to perform this postback; this code is automatically added by ASP.NET and looks something like this:

 javascript:__doPostBack('dgComments:_ctl2:_clt2,''). 

NOTE

For more information on the JavaScript function confirm, be sure to refer to the sources listed in the "On the Web" section at the end of this chapter.


The challenge facing us is in altering HTML rendered by the Delete button so that it includes the client-side onclick event handler.

To help solve this problem, we can use the Attributes property of the Delete button. Realize that all Web controls contain an Attributes property that is a collection of attributes for the Web control. These attributes include client-side events like onblur, onmouseover, onclick, and others. We can specifically set an attribute of a Web control by programmatically setting the proper entry in the Web control's Attributes collection. That is, if we have a Web control, someControl, and we want to have a JavaScript alert dialog box popup whenever the user clicks the Web control, we could use the following code to specify the onclick attribute for the Web control:

 someControl.Attributes("onclick") = "javascript:alert('Hello, World!');" 

For example, if someControl were a Label Web control with its Text property set to "Click Me" and we added the preceding line of code to our ASP.NET Web page's Page_Load event handler, the HTML produced by the Label control would be as follows:

 <span  onclick="javascript:alert('Hello, World!');">     Click Me  </span> 

Using the Attributes collection, we can assign some client-side code to execute when the onclick client-side event is fired for our Delete button. However, we need some way to reference this Delete button. In Chapter 4, we saw how we could use the DataGrid's ItemDataBound event to programmatically set the Text and NavigateUrl properties of a HyperLinkColumn. Recall that the DataGrid's ItemDataBound event fires once for each row, immediately after the DataSource has been bound to the row.

By the time the DataGrid's ItemDataBound event fires, the Delete button has been created and added to the DataGridItem that constitutes the DataGrid row. Therefore, we can write an event handler for the DataGrid's ItemDataBound event that programmatically references the Delete button for the row and adds the client-side onclick event handler code using the Delete button's Attributes collection.

NOTE

We'll be discussing the ItemDataBound and ItemCreated events in much greater detail in the next chapter.


Listing 10.5 contains the code for the event handler for the DataGrid's ItemDataBound event.

Listing 10.5 The dgComments_RowDataBound Event Handler Sets the Delete Button's Client-Side onclick Event
  1: Sub dgComments_RowDataBound(sender as Object, e As DataGridItemEventArgs)   2:     If e.Item.ItemType <> ListItemType.Header AND _   3:         e.Item.ItemType <> ListItemType.Footer then   4:       Dim deleteButton as LinkButton = e.Item.Cells(1).Controls(0)   5:   6:       'We can now add the onclick event handler   7:       deleteButton.Attributes("onclick") = "javascript:return " & _   8:            "confirm('Are you sure you want to delete this record?');"   9:     End If  10: End Sub 

The dgComments_RowDataBound event handler is fairly simple. The event handler fires for both item rows in the DataGrid and header and footer rows, but because there is no Delete button in the header or footer rows, we need to ensure that we're not dealing with such a row before trying to programmatically set the Delete button's client-side onclick event. Such a check is made on line 2, determining whether the current DataGridItem's ItemType property is of the type ListItemType.Header or ListItemType.Footer. If it is neither of these, the code from lines 4 through 8 executes.

On line 4, the Delete button is referenced. Because the Delete button is in the second column of the DataGrid, we access the DataGridItem's Cells(1) property to get the second TableCell. Because the Delete button is the sole control in the column, we can reference it using the TableCell's Controls collection, Controls(0). After we have this Delete button referenced as a local variable, we can go ahead and set the button's Attributes collection so that the client-side onclick event fires a specified block of JavaScript (lines 7 and 8).

After adding the event handler in Listing 10.5 to our ASP.NET Web page from Listing 10.4, we need to wire up the DataGrid's ItemDataBound event to this event handler. This can be easily accomplished by adding the following line of code to the DataGrid declaration immediately after line 48 in Listing 10.4:

 OnItemDataBound="dgComments_RowDataBound" 

After the DataGrid's ItemDataBound event has been wired up to the dgComments_RowDataBound event handler, whenever a user clicks a Delete button, he will be prompted with a confirm dialog box, as shown in Figure 10.6. If the user clicks the confirm dialog box's Cancel button, the row will not be deleted.

Figure 10.6. A client-side dialog box appears when the user clicks any Delete button.

graphics/10fig06.gif

The astute reader will have noticed that we could have added the client-side onclick event handler to the Delete button when the DataGrid's ItemCreated event fired. Although this is true, there is a benefit to setting the Delete button's Attributes collection in an event handler for the DataGrid's ItemDataBound event. The advantage is that when the ItemDataBound event fires, we can access the values of the DataSource that are being bound to this particular row. This means that we can provide a more descriptive client-side confirm dialog box.

For example, if we change lines 7 and 8 in Listing 10.5 to

 deleteButton.Attributes("onclick") = "javascript:return " & _     "confirm('Are you sure you want to delete the following " & _     "comment?\n\n" & _     Regex.Replace(DataBinder.Eval(e.Item.DataItem, "Name"), "'", "\'") & _     "\n" & _     Regex.Replace(DataBinder.Eval(e.Item.DataItem, "Comment"), "'", "\'") & _     "');" 

when the user clicks a Delete button, she will be shown a confirm dialog box that not only asks her if she wants to delete the comment, but also shows her the author of the comment and the actual comment itself, as seen in Figure 10.7.

Figure 10.7. The client-side confirm dialog box contains more information about the comment to be deleted.

graphics/10fig07.gif

NOTE

The Regex.Replace method replaces all apostrophes (') with escaped apostrophes (\') . It is vital to replace such characters; otherwise, if the Comment or Name fields from the DataSource contain any apostrophes, the confirm call won't fire because you'll have a malformed input string to the confirm function. Specifically, you'll have a string like


 'Are you sure you want to delete the following: It's nice to be here!' 

The apostrophe between the tand sin It's ends the string, meaning the remaining characters are interpreted as usual JavaScript syntax.

This case is equivalent to displaying double quotes in a string in Visual Basic .NET. For example, to assign a string the value

 Bob said, "Hi." 

you'd have to use the following code in Visual Basic .NET:

 SomeString = "Bob said, ""Hi.""" 

Here two successive double quotes are used to signify that it should be interpreted as a single double quote within the string, not the termination of the string. JavaScript, however, like C#, uses the backslash character (\) to escape apostrophes and double quotes.



ASP. NET Data Web Controls Kick Start
ASP.NET Data Web Controls Kick Start
ISBN: 0672325012
EAN: 2147483647
Year: 2002
Pages: 111

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