The Big ASP.NET DataGrid Article, Part 3, Page 2
You may remember the Edit-Update-Cancel button we added earlier. When the user clicks "Edit", the EditCommand of the DataGrid fires off. And that's exactly the event this next block of code should run in response to:
' Select the current row for 'edit mode' MyDataGrid.EditItemIndex = e.Item.ItemIndex ' Refill DataSets with information ParentNewsArticleDataAdapter.Fill(MyDataSet) ChildReporterDataAdapter.Fill(MyDataSet) ' Rebind data MyDataGrid.DataBind() ' Select default dropdown option, as earlier Dim ddl As DropDownList = _ CType(MyDataGrid.Items(MyDataGrid.EditItemIndex). _ FindControl("ddl2"), DropDownList) ddl.SelectedIndex = _ ddl.Items.IndexOf( _ ddl.Items.FindByValue(e.Item.Cells(FOREIGN_KEY_COL_NUM).Text))
Much of the code here is typical of that you'd find responding to an edit event. We set the .EditItemIndex. We populate our DataSets again and rebind. Then, we run special code to locate our second dropdown (the editable one) and preselect the correct default value (again, replace FOREIGN_KEY_COL_NUM with the column number containing your foreign key value). Great stuff.
What's left to do? Well, we've handled displaying a default item in regular "view" mode and pre-selecting one in edit mode. The user will then begin editing the grid—and when finished, either click "Update", wishing to store their changes, or "Cancel" to forget about them.
Figure: Visualizing the "Update" and "Cancel" options our user will have after clicking 'Edit'
When the user clicks "Update", the DataGrid UpdateCommand event runs—then it's over to you to take the alterations and update your database. That's just what this next chunk of slightly-more-confusing code does, to be run in response to the UpdateCommand event:
' Step one: Put dropdown list value into foreign key field Ctype.Item.Cells(FOREIGN_KEY_COL_NUM).Controls(0), TextBox).Text = _ CType(e.Item.FindControl("ddl2"), DropDownList).SelectedItem. _ Value() ' Step two: Fill DataSet and identify row to edit ParentDataAdapter.Fill(MyDataSet) ChildDataAdapter.Fill(MyDataSet) Dim objEditedRow As DataRow = MyDataSet.Tables(0).Rows.Find( _ CType(e.Item.Cells(ID_NUM).Controls(0), TextBox).Text) ' Step three: Cycle through valid "data" cells and put ' information back in underlying DataSet Dim intCount As Integer For intCount = 0 To e.Item.Cells.Count - 1 If e.Item.Cells(intCount).Controls.Count > 0 Then If TypeOf (e.Item.Cells(intCount).Controls(0)) Is TextBox Then ' This appears to be a TextBox-holding "data" cell Dim strValue As String = CType(e.Item.Cells(intCount). _ Controls(0), TextBox).Text ' Put value (or null if empty) back into relevant DataSet ' field If strValue = "" Then objEditedRow.Item(MyDataGrid.Columns(intCount). _ SortExpression) = System.DBNull.Value Else objEditedRow.Item(MyDataGrid.Columns(intCount). _ SortExpression) = strValue End If End If End If Next ' Update backend data ParentNewsArticleDataAdapter.Update(MyDataSet) ' Deselect DataGrid items and rebind With MyDataGrid .SelectedIndex = -1 .EditItemIndex = -1 .DataSource = MyDataSet .DataBind() End With
This code consists of three core steps. In the first, we retrieve the value behind our dropdown and put it in the foreign key field (replace FOREIGN_KEY_COL_NUM with the column number containing your foreign key value). In the second, we fill our DataSet as normal, and then filter using the primary key value to locate the row our user has edited (replace ID_NUM with the column number of your primary key value). The third and final step cycles through all the cell TextBox controls, figures out which field the data inside each box belongs to (using the column sort expression value), and updates the underlying DataSet. We then deselect any DataGrid items and rebind. It looks confusing, and the DataGrid does none of the work for us, but the underlying process is actually relatively simple.
Finally, we need to add code to respond just in case the user clicks "Cancel". This is relatively standard code and should be added to respond to the CancelCommand event. We simply reset the grid and rebind:
MyDataGrid.SelectedIndex = -1 MyDataGrid.EditItemIndex = -1 ParentNewsArticleDataAdapter.Fill(MyDataSet) ChildReporterDataAdapter.Fill(MyDataSet) MyDataGrid.DataBind()
And that's it! Admittedly, it seems one heck of a long process for something so relatively simple, but, if you've seen some of the other demonstrations of this technique elsewhere, you'll appreciate the concise nature of this blighter. And, once you've done it a couple of times, well, let's just say it gets a little easier. Phew.
Top Tip: For simplicity and to ensure this tip can run "standalone", it uses the standard Edit-Update-Cancel button integrated into the DataGrid. If you're building on top of the "Nine Steps to a Quick, Editable Web Grid" tip, you may wish to edit certain parts of this code so it kicks in behind your own Edit-Update-Cancel buttons and possibly uses the DataSave, DataRetrieve, and DataExists routines. You may also want to add your own error handling or concurrency checks, too. Or you might just decide you've already pushed editing with the DataGrid too far and opt for a third party-solution. Your call.
Figure: Give yourself a promotion: demonstrating an editable Web grid dropdown