Editing Data on the Grid

IOTA^_^    

ASP.NET Developer's JumpStart
By Paul D. Sheriff, Ken Getz
Table of Contents
Chapter 17.  Editing Data Using the DataGrid Control


It's useful to be able to navigate to a new page to edit a full row, but what if you would rather edit data right in the grid? The DataGrid control makes this possible, and, if you're happy with the default layout, extremely easy. By setting a few properties, you can allow users to edit data right in the grid. By writing a little code, you can save the data back out to the original data source.

To add the Edit button to each row (and the associated Cancel and Update buttons, which only display while you're editing a row), you follow the same sorts of steps you used in order to add the Hyperlink column the Property Builder makes it simple. To add the Edit button, follow these steps:

  1. Open ProductsEdit.aspx in the page designer.

  2. Right-click the DataGrid control and select Property Builder from the context menu.

  3. Select the Columns tab to display information about the columns displayed in the DataGrid control.

  4. From the Available Columns list, expand the Button Column node. Select Edit/Update/Cancel and then click the > button to add a new column to the Selected Columns list.

  5. Click the up-arrow button repeatedly until the new column is first in the list of available columns.

  6. Even though you won't use the Delete link until later in the chapter, select the Delete item in the Available Columns list, add it to the Selected Columns list, and move it up until it's the second item in the list.

  7. When you're done, click OK to dismiss the dialog box.

TIP

If you'd rather display a standard button instead of a link, you can change the ButtonType property to PushButton, rather than LinkButton, before you dismiss the Properties dialog box.


Once you're done, you should immediately see a new column on the left side of the DataGrid control the Edit column. Unfortunately, editing comes at a price you must add some code to your page in order to activate editing as well as more code to handle the Cancel and Update buttons that appear while you're editing.

Beginning the Editing

When you click the Edit link on the DataGrid control, the control posts the page back and raises the EditCommand event on the server. In order to render the DataGrid control so that you can edit the selected row, you must set the control's EditItemIndex property, indicating which row it should be editing. (If no row is being edited, the EditItemIndex property is -1.) How can you determine which row you clicked? The EditCommand event handler receives, as its second parameter, a DataGridCommandEventArgs object. This object provides an Item property corresponding to the item (or row of data) that you selected. The Item property, an object itself, provides an ItemIndex property that contains the row number you need. Therefore, your EditCommand property will include at least this line of code (assuming that grdProducts is the name of your DataGrid control):

 grdProducts.EditItemIndex = e.Item.ItemIndex 

If you try out the sample page, you'll see that clicking the Edit link on a row places you in editing mode and replaces the Edit link with Save and Cancel links. Any modifiable cell in the grid displays as an editable control, and you can modify the data.

Listing 17.4 shows the sample page's EditCommand code.

Listing 17.4 The EditCommand Event Code Runs When You Click the Edit Link on the DataGrid Control
 Private Sub grdProducts_EditCommand( _  ByVal source As Object, _  ByVal e As System.Web.UI.WebControls. _  DataGridCommandEventArgs) _  Handles grdProducts.EditCommand   Dim ds As DataSet   Dim dv As DataView   ' Rehydrate the DataSet into a DataView   ' You must use a DataView in order to   ' use the RowFilter property.   ds = CType(Session("DS"), DataSet)   dv = ds.Tables(0).DefaultView   If IsIE5() Then     ' If this is IE5 or higher,     ' smart navigation will display the     ' edited row in the same place     ' as on the original page.     grdProducts.EditItemIndex = e.Item.ItemIndex   Else     ' If this isn't IE5 or higher, you need     ' to only show the one row being     ' edited. Otherwise, users would have     ' to scroll down to the row.     grdProducts.EditItemIndex = 0     dv.RowFilter = "ProductID = " & e.Item.Cells(2).Text   End If   grdProducts.DataSource = dv   grdProducts.DataBind()   Session("AddMode") = False   lnkAdd.Visible = False End Sub 

Rather than looking at the procedure sequentially, the following sections break the code up by functionality, describing each chunk of code in detail. There are quite a few new issues covered here, and it's worth discussing each in some depth.

Handling the Data

The EditCommand event handler runs after you've clicked the Edit link for a row in the DataGrid control. You must tell the grid which row it should be editing, and you must rebind the DataGrid control to its data source. (Remember, you're rendering the page and its contents because clicking the Edit link forced a roundtrip to the server. If you don't bind the control to its data source, it simply won't display any data!) The procedure uses this code to "rehydrate" the DataSet object that the page previously stored in a Session variable, and it uses the DefaultView property to retrieve a DataView object based on the only table in the DataSet:

 Dim ds As DataSet Dim dv As DataView ... ds = CType(Session("DS"), DataSet) dv = ds.Tables(0).DefaultView 

Why do you need a DataView object here? Normally, you could simply bind the DataGrid control to a DataSet and be done with it. In this case, however, depending on the browser that requested the page, you may need a DataView object to find the row you need. (The next section solves this mystery for now, just believe us.)

Given the DataView object, the code sets up the data source and rebinds the DataGrid control:

 grdProducts.DataSource = dv grdProducts.DataBind() 
Managing the Grid

If you're testing the sample page using Internet Explorer 5.01 or later (and chances are good that this is a safe assumption), you probably noticed how nicely the browser maintains your position on the page when it rerenders after you click the Edit button. Perhaps you didn't even think about it, forgetting that you've posted back to the same page, making a roundtrip to the Web server. This isn't behavior you would normally expect when rendering a page, yet IE 5.01 (or later) and the ASP.NET page framework make it happen.

The magic in use here is a feature named SmartNavigation. This is a server-side feature provided by the ASP.NET page framework, and it makes postbacks to a page look better, if the request comes from IE5 or later. Specifically, SmartNavigation makes postbacks look better by performing these tasks:

  • Eliminating the flash/flickering caused by page navigation

  • Saving your position on the page so that when the browser displays the same page, you're at the same location on the page

  • Persisting the focus across postbacks so that you're in the same control before and after a postback

NOTE

SmartNavigation only saves information for a single page. As soon as you navigate elsewhere, all "smart" information is lost for the page.


This technology works great if the page request comes from a sufficiently enabled browser all you need to do is set the SmartNavigation property for your page to True, and you're all set. As a matter of fact, the Page_Load procedure in the sample page sets this property for you:

 Private Sub Page_Load( _  ByVal Sender As System.Object, _  ByVal e As System.EventArgs) Handles MyBase.Load   If Not Page.IsPostBack Then     Session("AddMode") = False     GridLoad()   End If   Page.SmartNavigation = True End Sub 

If SmartNavigation is enabled, you can simply send the user back to the originally selected row. To do that, your code must set the EditItemIndex property to be the selected row, like this:

 grdProducts.EditItemIndex = e.Item.ItemIndex 

What about users who can't use the SmartNavigation feature? You can't really start editing the same row, because that row might be far down the page. Imagine what the user sees: After scrolling down the final row, for example, and clicking the Edit link, the page refreshes back at the top the user has to scroll down to the bottom again to edit the row that was just clicked! Not good. We suggest you avoid this situation by displaying only the single row the user has selected for editing. To do that, the sample page's EditCommand procedure uses this code:

 dv.RowFilter = "ProductID = " & e.Item.Cells(2).Text grdProducts.EditItemIndex = 0 

This code first retrieves the Text property from the cell within the selected row that contains the product ID (e.Item.Cells(2).Text) and builds up a filter expression. The code assigns the filter to the RowFilter property of the DataView object that contains the grid's data. This code effectively filters the DataView object so that it contains only a single row. The next line of code sets the EditItemIndex property of the grid to 0. Because the grid will only be showing a single filtered row, this is the index you need.

In order to determine which path through the code to take, the sample page includes a function, IsIE5, that determines the capabilities of the browser that made the request to the page:

 Private Function IsIE5() As Boolean   ' Check to see if the browser causing the   ' request was IE5 or higher.   With Request.Browser     IsIE5 = ((.Browser = "IE" And .MajorVersion >= 5) _      And Not FORCEDOWNLEVEL)   End With End Function 

This function uses the Browser property of the Request object, checking the Browser and MajorVersion properties. In addition, the page includes the constant FORCEDOWNLEVEL, which is by default set to False. If you set this to True, you'll force the IsIE5 function to return False, allowing you to test the behavior on down-level browsers.

If you want to test out this behavior, and you only have a browser that supports SmartNavigation, set the FORCEDOWNLEVEL constant to True in the code:

 Private Const FORCEDOWNLEVEL As Boolean = True 

Then, display ProductsEdit.aspx in your browser, click the Edit link for a row, and you should see only that one row displayed in the posted page. Figure 17.5 shows how the page might look after clicking the Edit link, once you've set the FORCEDOWNLEVEL constant to True (or if you've browsed to the page from a down-level browser).

Figure 17.5. With a down-level browser, you'll most likely only want to display a single row for editing it's less confusing to the user.

graphics/17fig05.jpg

The whole chunk of code that handles the grid looks like this:

 If IsIE5() Then   ' If this is IE5 or higher,   ' smart navigation will display the   ' edited row in the same place   ' as on the original page.   grdProducts.EditItemIndex = e.Item.ItemIndex Else   ' If this isn't IE5 or higher, you need   ' to only show the one row being   ' edited. Otherwise, users would have   ' to scroll down to the row.   grdProducts.EditItemIndex = 0   dv.RowFilter = "ProductID = " & e.Item.Cells(2).Text End If 

TIP

Obviously, we didn't dwell on either of the topics introduced here: the Cells property of the current row or the RowFilter method of a DataView object. You can certainly research both of these topics in the online help. For now, it's important to understand that the DataGrid control provides the selected row to your event procedure as the Item property (e.Item) and that row provides a collection of cells (e.Item.Cells(2), for example). If the cell contains controls (while you're editing, some cells contain TextBox controls, for example), each Cell object provides a Controls collection that allows you to access the controls inside each cell.


Adding Versus Editing

The ProductsEdit.aspx page treats adding a new row and editing an existing row in almost the same way, and even sharing some of the same code. (When you think about it, aren't these really similar operations? Once you add a blank row to contain the new data, editing and adding are the same, from then on, for the most part.) The real differences come when it's time to update the data when adding, the code must create an INSERT SQL statement; when updating, the code uses an UPDATE SQL statement instead. The sample code keeps track of two different items, based on whether you're adding or editing:

  • The Add a New Product link at the top of the page disappears if you're currently editing a row, and it reappears when you're done.

  • The Session variable AddMode keeps track of whether you're in Add mode.

The grdProducts_EditCommand procedure handles both of these before it finishes, using this code:

 Session("AddMode") = False lnkAdd.Visible = False 

Because this code only executes when you're entering edit mode, it must set the Session variable so that the code that saves the data knows you weren't in Add mode, and it also must hide the link that allows you to add a new row.

Saving the Data

When you click the Update link on the current row, you trigger a postback to the server, and the page runs the DataGrid control's UpdateCommand event handler. This procedure must perform the following tasks:

  • Retrieve the modified items from the grid

  • Update the data in the data store

  • Reset the DataGrid control's EditItemIndex property so that it doesn't attempt to display any row in edit mode

  • Rebind the DataGrid control to its data source

In addition, the sample page must handle saving the data differently if you are editing a row, as opposed to adding a new row. You'll learn more about adding a new row in a later section, but for now, as you peruse the code, just remember that AddMode will be True if you select the link to add a new row, and it will be False otherwise.

The procedure shown in Listing 17.5 runs after you select the Update link for a row in edit mode.

Listing 17.5 Updating Data Requires a Bit of Code
 Private Sub grdProducts_UpdateCommand( _  ByVal source As Object, _  ByVal e As System.Web.UI.WebControls. _  DataGridCommandEventArgs) _  Handles grdProducts.UpdateCommand   Dim strProductID As String   Dim strName As String   Dim strUnitPrice As String   Dim strUnitsInStock As String   Dim strSQL As String   Dim strConn As String   Try     ' Retrieve edited items from grid     With e.Item       strProductID = .Cells(2).Text       strName = _        CType(.Cells(3).Controls(0), HyperLink).Text       strUnitPrice = _        CType(.Cells(4).Controls(0), TextBox).Text       strUnitsInStock = _        CType(.Cells(5).Controls(0), TextBox).Text     End With     ' Check to see if we are editing or adding     If CBool(Session("AddMode")) Then       strSQL = String.Format( _        "INSERT INTO Products(ProductName, " & _        "UnitPrice, UnitsInStock) " & _        "VALUES( {0}, {1}, {2}) ", _        DataHandler.QuoteString(strName), _        strUnitPrice, strUnitsInStock)     Else       strSQL = String.Format( _        "UPDATE Products " & _        "SET ProductName = {0}, " & _        "UnitPrice = {1}, " & _        "UnitsInStock = {2} " & _        "WHERE ProductID = {3}", _        DataHandler.QuoteString(strName), _        strUnitPrice, _        strUnitsInStock, strProductID)     End If     ' Submit SQL     strConn = Session("ConnectString").ToString     DataHandler.ExecuteSQL(strSQL, strConn)   Catch oException As Exception     lblError.Text = oException.Message     lblError.Visible = True   End Try   ' Reset Add flag, and reset the label.   Session("AddMode") = False   lnkAdd.Visible = True   ' Turn off editing, and re-bind the grid.   grdProducts.EditItemIndex = -1   Call GridLoad() End Sub 

The grdProducts_UpdateCommand requires some detailed explanation.

The procedure starts by retrieving values from the grid. This issue is somewhat complicated, because you must use both the Cells property of the item provided by the event procedure's parameter, and you must use the Controls collection provided by the individual cell. In order to understand the Cells collection, take a look at Figure 17.5. The Item property represents the entire row in the table, and the Cells collection starts numbering with 0. In this example, Cells(0) contains two controls (the Update and Cancel links), Cells(1) contains one control (the Delete link), and Cells(2) contains the ProductID value. The procedure retrieves the value of the ProductID using this statement:

 strProductID = .Cells(2).Text 

Cells(3) contains a HyperLink control, and the procedure retrieves its value using this code:

 strName = _  CType(.Cells(3).Controls(0), HyperLink).Text 

Because the Cells collection contains objects, and you need to retrieve the Text property of the hyperlink contained within the collection, you must use the CType function to convert the object into a HyperLink control so that you can retrieve the control's Text property.

The procedure continues, retrieving the value of the rest of the necessary controls, using this code:

 strUnitPrice = _  CType(.Cells(4).Controls(0), TextBox).Text strUnitsInStock = _  CType(.Cells(5).Controls(0), TextBox).Text 

If a cell contains more than a single control (you'll see an example of this later in the chapter), your code would need to take that into account, using Controls(1), for example, to retrieve the second control within a cell.

Once the procedure has retrieved the values from the grid, it takes one of two paths, depending on whether you're adding a new row or editing an existing one. (You'll see more on adding a new row later in this chapter.) If you're adding, the procedure builds a SQL INSERT statement; otherwise, it builds a SQL UPDATE statement:

 If CBool(Session("AddMode")) Then   strSQL = String.Format( _    "INSERT INTO Products(ProductName, " & _    "UnitPrice, UnitsInStock) " & _    "VALUES( {0}, {1}, {2}) ", _    DataHandler.QuoteString(strName), _    strUnitPrice, strUnitsInStock) Else   strSQL = String.Format( _    "UPDATE Products " & _    "SET ProductName = {0}, " & _    "UnitPrice = {1}, " & _    "UnitsInStock = {2} " & _    "WHERE ProductID = {3}", _    DataHandler.QuoteString(strName), _    strUnitPrice, _    strUnitsInStock, strProductID) End If 

Given the SQL statement appropriate to the action, the code retrieves the connection information and executes the SQL:

 strConn = Session("ConnectString").ToString DataHandler.ExecuteSQL(strSQL, strConn) 

Before the procedure finishes up, it resets the Add a New Product label and the Session variable AddMode:

 ' Reset Add flag, and reset the label. Session("AddMode") = False lnkAdd.Visible = True 

Finally, the procedure resets the DataGrid control's editing (indicating that no row is currently being edited) and rebinds the grid to its data:

 ' Turn off editing, and re-bind the grid. grdProducts.EditItemIndex = -1 Call GridLoad() 

Cancelling the Edit

If you're in the middle of editing a row and decide to cancel, you can select the Cancel link on the row (see Figure 17.5). When you do, you trigger a postback to the server, where the page runs the CancelCommand event handler for the control. All you need to do in this procedure is indicate to the control that you're no longer editing and then rebind the data to the grid.

To reset the edit mode, you simply set the EditItemIndex property of the DataGrid control to -1. The CancelCommand event handler in the sample page looks like this:

 Private Sub grdProducts_CancelCommand( _   ByVal source As Object, _   ByVal e As System.Web.UI.WebControls. _   DataGridCommandEventArgs) _   Handles grdProducts.CancelCommand   grdProducts.EditItemIndex = -1   Call GridLoad()   lnkAdd.Visible = True End Sub 

    IOTA^_^    
    Top


    ASP. NET Developer's JumpStart
    ASP.NET Developers JumpStart
    ISBN: 0672323575
    EAN: 2147483647
    Year: 2002
    Pages: 234

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