Here is a solution I came up with for an editable grid that can be made editable with single button click outside the grid. There is also a cancel edit button and submit changes button. The table schema and data is dynamic, the table name we are binding to is dataTable and the column names are stored in MyMappedColumns List.
<input type="button" value="Edit Invalid Records" id="editErrorGrid" />
<input type="button" value="Cancel Record Editing" id="cancelEditErrorGrid" />
<input type="hidden" value="False" id="editErrorGridValue" runat="server" />
<asp:Button Text="Submit Changes" ID="btnSubmitChanges" runat="server" OnClick="btnSubmitChanges_Click" />
<asp:GridView ID="GridView" runat="server" OnRowDataBound="GridView_OnRowDataBound"></asp:GridView>
protected void GridView_OnRowDataBound(object sender, GridViewRowEventArgs e) {
var totalColumns = e.Row.Cells.Count;
var columnCount = MyMappedColumns.Count;
GridView grid = (GridView) sender;
for (int i = 1; i < totalColumns; i++) {
if (e.Row.RowType == DataControlRowType.DataRow) {
//add a textbox and a label in each row cell, except the first column is the primary key, so we don't make that editable.
var text = e.Row.Cells[i].Text.Equals(" ") ? string.Empty : e.Row.Cells[i].Text;
TextBox input = new TextBox() { Text = text, ID = string.Format("{0}_{1}_errTxt", e.Row.RowIndex, i) };
e.Row.Cells[i].Controls.Add(input);
Label lbl = new Label() { Text = text, ID = string.Format("{0}_{1}_errLbl", e.Row.RowIndex, i) };
e.Row.Cells[i].Controls.Add(lbl);
}
}
}`
The page has the following JavaScript code to make the grid editable, and cancel editing.
jQuery(document).ready(function() {
//Hide the textboxes inside the grid.
jQuery("input[id$=errTxt]").hide();
jQuery("input[id$=btn_reValidateRecords]").addClass('hidden');
jQuery("#editErrorGrid").addClass('hidden');
jQuery("#cancelEditErrorGrid").addClass('hidden');
jQuery("#editErrorGrid").click(function() {
jQuery("input[id$=editErrorGridValue]").val("True");
jQuery("span[id$=errLbl]").hide();
jQuery("input[id$=errTxt]").show();
jQuery("#editErrorGrid").addClass('hidden');
jQuery("#cancelEditErrorGrid").removeClass('hidden');
});
jQuery("#cancelEditErrorGrid").click(function() {
jQuery("input[id$=editErrorGridValue]").val("False");
jQuery("span[id$=errLbl]").show();
jQuery("input[id$=errTxt]").hide();
jQuery("#cancelEditErrorGrid").addClass('hidden');
jQuery("#editErrorGrid").removeClass('hidden');
});
});
Finally, on postback from btnSubmitChanges_Click, we can read the values from the grid, given the last row containing the primary key id:
protected void btnSubmitChanges_Click(object sender, EventArgs e) {
for (int j = 0; j < GridView.Rows.Count; j++) {
GridViewRow row = ErrorsGridView.Rows[j];
var _table_id = row.Cells[0].Text;
//itterate through all the table rows except first Primary Key, which is not editable
for (int i = 1; i < MyMappedColumns.Count; i++) {
//each table cell has a input textbox and a label
var cellName = row.Cells[i].ClientID.Split('_');
StringBuilder errTxtName = new StringBuilder(cellName[0]);
errTxtName.AppendFormat("${0}${1}${2}", cellName[1], cellName[2], cellName[3]);
errTxtName.AppendFormat("${0}_{1}_ErrTxt", j, i);
//get the text and update my table
var errTxt = Request.Form[errTxtName.ToString()];
var errRow = dataTable.Rows.Find(_table_id);
//handle empty text
if (errTxt.Length == 0)
errRow[MyMappedColumns[i]] = DBNull.Value;
else
errRow[MyDataImport.MyMappedColumns[i]] = errTxt;
}
}
}