.NET Discussion

.NET Issues, Problems, Code Samples, and Fixes

ASP.NET: GridView Update/Edit/Cancel, HyperLinkFields, and DataKey Retrieval

Today was spent mostly tackling the GridView’s Update/Edit functionality, and I got incredibly frustrated, at first. This was my first foray into this part of the GridView’s functionality, since I haven’t really had to develop anything using it since the switch to 2.0, as everything in DataGrids still functioned fine. With a little bit of research, a lot bit of patience, and some help from the internet community, I was able to solve all my issues, and pretty elegantly at that.

Basically, I was trying to convert an existing data-display-only GridView (ie, no special functions) into one where I can update a field, namely the inventory for displayed products. After working with DataGrids so efficiently, I was scared that GridViews were going to be a million times more complex. I suppose my eyes got big when I saw all the new properties and methods, and wanted to try them all out.  Big mistake.

Most articles I found were for hardcoded datasources (especially on MSDN, ugh) and didn’t really help me much, so this post will be referring to GridViews with dynamically bound datasources. First, create a GridView with three bound columns and an Update/Edit/Cancel (CommandField) column:

<asp:gridview id="GridView1" runat="server" autogeneratecolumns="False" onrowediting=GridView1_RowEditing datakeynames="productid" onrowcancelingedit=GridView1_RowCancelingEdit onrowupdating=GridView1_RowUpdating>
       <columns>
       <asp:hyperlinkfield datanavigateurlfields="productid" datanavigateurlformatstring="/products/index.aspx?productid={0}" text="Product" target="_blank" />
        <asp:boundfield datafield="inventory" headertext="Inventory" />
        <asp:commandfield showeditbutton="True" />
        <asp:boundfield datafield="productid" visible="false" />
       </columns>
      </asp:gridview>

Nothing in there should be shocking to anyone: all your events are handled, you have a HyperLinkField that uses the DataNavigateURLFields property to insert a ProductID, and you have set your DataKeyNames property to your hidden field which holds your ProductID.

Because we are not using the GridView’s built-in data model and are binding dynamically, the GridView will not switch into and out of Edit Mode automatically. Thus, in order to switch it into Edit Mode, in each of your event handles (RowEditing, RowUpdating, and RowCancelingEdit) you must do two things:

  1. Change the GridView’s EditIndex appropriately
  2. Re-bind your GridView

These are both very easy to do, and your RowEditing and RowCancelingEdit handles should be simple, like this: 

Protected Sub GridView1_RowEditing(ByVal sender As System.Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs)

GridView1.EditIndex = e.NewEditIndex 'set to selected row
BindGridView() ' your own subroutine that you use to bind your datagrid

End Sub

Protected Sub GridView1_RowCancelingEdit(ByVal sender As System.Object, ByVal e As System.Web.UI.WebControls.GridViewCancelEditEventArgs)

GridView1.EditIndex = -1 'set to no selection
BindGridView()

End Sub

One issue I ran into while attempting to figure this all out was if I didn’t rebind my GridView at the end of each event, I was required to click twice to get it to select the correct row, and if I clicked around, it would always be a row behind. So be sure to rebind your GridView at the end of your event handler. 

The RowUpdating event is where it gets tricky, since pulling values is not necessarily intuitive. You can’t do something like GridView1(i)(j).Text = str or anything even close. Instead, you must cast the cells as controls. Here’s an example of how I did it in my RowUpdating event handler:

Dim name As HyperLink
Dim inv As TextBox

name = CType(GridView1.Rows(e.RowIndex).Cells(0).Controls(0), HyperLink)
inv = CType(GridView1.Rows(e.RowIndex).Cells(1).Controls(0), TextBox) ' .Cells(1) refers to the 2nd column

Once you’ve casted them, you can now easily get their values by invoking their .Text property, ie, name.Text. Remember that my first column was a HyperLinkField, so in order to pull that value, I must cast that column as a HyperLink.

Finally, to pull your hidden value that you’ve dubbed a DataKey in the GridView’s DataKeyNames property, do the following:

Dim ProductID as Integer = GridView1.DataKeys(e.RowIndex).Value

EDIT 3/5/08: I forgot to mention in this article how to retrieve “Read-Only” data. You cannot convert a read-only cell into a textbox, so you must retrieve the value another way:

Dim str as String = GridView1.Rows(e.RowIndex).Cells([your cell]).Text

Then do whatever you need to do to update your database, set the EditIndex to -1, and call your BindGridView() subroutine. Everything should be sorted out when the “Update” link is pressed. To enhance this process, be sure to include your GridView in an AJAX UpdatePanel.

Hope this saves someone a full day of research (and possibly some hair)!

kick it on DotNetKicks.com

September 26, 2007 Posted by | AJAX, ASP.NET, GridView, Tips & Tricks | 148 Comments