The DataGrid provides row-by-row editing capabilities via the following players:
- The EditCommandColumn DataGridColumn, which renders a column of Edit/Update/Cancel buttons in the DataGrid.
- The
EditItemIndex property, which indicates the index of the row that is editable, and
- The DataGrid databinding process, which enumerates the DataSource and creates a DataGridItem for each record
- The
EditCommand/UpdateCommand/CancelCommand events, which fire when the Edit/Update/Cancel buttons are clicked. These events are useful because a page developer will create an event handler and perform the steps necessary to provide editing capabilities (such as setting the EditItemIndex property accordingly, issuing an UPDATE statement to the database, and so on....)
These four actors make editing database data on a row-by-row basis a relatively simple task, much much much simpler than was possible in classic ASP. Some situations, though, require a fully editable DataGrid, one where all rows are editable at once, rather than on a row-by-row basis. In such scenarios, the end user wants to be able to make any number of changes and then click an "Update All" button.
The DataGrid does not provide this capability inherently. In my book, ASP.NET Data Web Controls Kick Start, I examine how to use a standard DataGrid to provide such functionality, namely through making each editable column in the DataGrid a TemplateColumn where the TemplateColumn's ItemTemplate has the editing interface (such as a TextBox Web control, or DropDownList, or whatever Web control(s) is/are suitable for the editing interface). Additionally, a "Save All" button is included that, when clicked, iterates through the DataGrid's Items collection and issues an UPDATE statement for each DataGrid row. While this approach clearly works, it is a departure from the DataGrid's existing functionality for doing updates.
With these thoughts, I set out to create a fully editable custom control derived from the DataGrid class. My vision was to have a control that provided full editing capabilities via:
- Some means to display "Edit All Rows"/"Update All Rows"/"Cancel Batch Update" buttons, similar to the Edit/Update/Cancel buttons in each row for the row-by-row editable DataGrid. Rather than having these buttons appear in each row, though, I'd just want them to appear once, like maybe above the DataGrid.
- A
BatchUpdate property - if true, all rows would be displayed as editable, if false, none would. Therefore, a page developer could toggle between all rows being editable or not by setting this property and rebinding the data to the grid.
EditBatchCommand/UpdateBatchCommand/CancelBatchCommand events, which the page developer could create event handlers for to take the necessary steps to update the database, or to toggle the BatchUpdate value.
Initially this seemed like an easy task. Created a class that derived from DataGrid, added a BatchUpdate property, overrode the DataGrid's CreateItem() method so that if an Item or AlternatingItem was being created and BatchUpdate was True, then the DataGridItem was created as an EditItem. Added the events, and then set out to add the buttons. And that's where I got stuck.
Initially I thought I'd just override the CreateChildControls() method and add buttons to the start of the control hierarchy, thereby having them appear above the DataGrid. No dice, as the DataGrid's PrepareControlHierarchy() method naively assumes that the first control in the hierarchy is the DataGrid's Table control. This approach worked, though, if I slapped the buttons at the end of the control hierarchy, but then the buttons would always appear at the bottom of the grid, and I wanted more flexibility.
An ideal approach, I reckoned, would to be to create a new DataGridItem type, like the Pager type, that would add a row to the top and/or bottom of the DataGrid with the buttons. However, this would involve a major reworking of the DataGrid, requiring the overriding of many methods and classes. Way more work than I wanted to do.
My end solution - and here's where I'm looking for comments - was to separate out the functionality into two server controls. An editable grid called EditGrid, and what I call an EditBar. The EditBar displays the "Edit All Rows"/"Update All Rows"/"Cancel Batch Update" buttons and has a property EditGridID, which must refernece the ID property of the EditGrid the EditBar works for. Then, when one of the EditBar's button is clicked, the appropriate EditGrid event is raised. Separating the EditGrid and EditBar has the advantage that the EditBar can be placed anywhere on the page and operate on the EditGrid, but it feels "messy" to me to have a control reference another control. I know the validation controls use a technique not unlike this with their ControlToValidate property, but I was wondering if anyone could think of a better way.
Any comments/ideas/suggestions most appreciated. For the record, I am working on an article on this topic, so any ideas or improvements suggested that are utilized will be given full credit in the article, naturally. Thanks!