在 ASP.NET 中编辑单个 GridView 单元格






4.88/5 (80投票s)
在不将整行置于编辑模式的情况下,编辑单个 GridView 单元格。示例包含使用 SqlDataSource 和 ObjectDataSource 控件。
引言
ASP.NET 的 GridView
通过设置 GridView
的 EditIndex
属性,可以将整行数据置于编辑模式进行编辑。
如果您正在为 EditItemTemplate
中的多个列使用 DropDownList
控件,您可能不希望将整行都置于编辑模式。如果每个 DropDownList
都有很多选项,一次性加载所有选项可能会导致页面响应缓慢。此外,如果您的数据结构更像一个二维数组而不是一组行,您可能希望单独编辑每个单元格。
在这里,我将演示如何实现这一点,以及如何处理 Event Validation 而无需禁用它。
背景
本文基于我之前一篇博文的读者提问:ASP.NET 中 GridView 和 DataList 控件的可点击和双击行。
要理解使 GridView
行可点击的概念,您可能希望在继续之前阅读它。
编辑单个 GridView 单元格

演示中的 GridView
在第一列有一个名为 SingleClick
的 asp:ButtonField
控件,其可见性设置为 false
。
这用于向 GridView
行添加点击事件。
<Columns>
<asp:ButtonField Text="SingleClick" CommandName="SingleClick"
Visible="False" />
</Columns>
对于其他列,都有一个带有可见 Label
控件和不可见 TextBox
、DropdownList
或 CheckBox
控件的项模板。
为了方便起见,我们将 Label
称为“显示控件”,将 TextBox
、DropdownList
或 CheckBox
称为“编辑控件”。
<asp:TemplateField HeaderText="Task">
<ItemTemplate>
<asp:Label ID="DescriptionLabel" runat="server"
Text='<%# Eval("Description") %>'></asp:Label>
<asp:TextBox ID="Description" runat="server"
Text='<%# Eval("Description") %>' Width="175px"
visible="false"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
这里的想法是,最初数据显示在显示控件中,当包含显示控件的单元格被点击时,其可见性设置为 false
,编辑控件的可见性设置为 true
。EditItemTemplate
未被使用。
在 RowDataBound
事件中,行中的每个单元格都会被循环遍历并添加点击事件。
单元格索引作为事件参数传入,以便在引发事件时可以识别单元格。
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Get the LinkButton control in the first cell
LinkButton _singleClickButton = (LinkButton)e.Row.Cells[0].Controls[0];
// Get the javascript which is assigned to this LinkButton
string _jsSingle = ClientScript.GetPostBackClientHyperlink(
_singleClickButton, "");
// Add events to each editable cell
for (int columnIndex = _firstEditCellIndex; columnIndex <
e.Row.Cells.Count; columnIndex++)
{
// Add the column index as the event argument parameter
string js = _jsSingle.Insert(_jsSingle.Length - 2,
columnIndex.ToString());
// Add this javascript to the onclick Attribute of the cell
e.Row.Cells[columnIndex].Attributes["onclick"] = js;
// Add a cursor style to the cells
e.Row.Cells[columnIndex].Attributes["style"] +=
"cursor:pointer;cursor:hand;";
}
}
}
在 RowCommand
事件中,会检索命令参数和事件参数。这为我们提供了所选单元格的行和列索引。
int _rowIndex = int.Parse(e.CommandArgument.ToString());
int _columnIndex = int.Parse(Request.Form["__EVENTARGUMENT"]);
由于已知所选单元格的行和列索引,可以通过将显示控件的可见性设置为 false
,将编辑控件的可见性设置为 true
来将单元格置于编辑模式。
选定单元格的属性也会被清除,以移除点击事件。
// Get the display control for the selected cell and make it invisible
Control _displayControl =
_gridView.Rows[_rowIndex].Cells[_columnIndex].Controls[1];
_displayControl.Visible = false;
// Get the edit control for the selected cell and make it visible
Control _editControl =
_gridView.Rows[_rowIndex].Cells[_columnIndex].Controls[3];
_editControl.Visible = true;
// Clear the attributes from the selected cell to remove the click event
_gridView.Rows[_rowIndex].Cells[_columnIndex].Attributes.Clear();
还有一些代码可以在回发后将焦点设置到编辑控件。如果编辑控件是 DropDownList
,则将其 SelectedValue
设置为显示控件的值;如果它是 TextBox
,则选中其文本以便进行编辑;如果它是 Checkbox
,则将其 checked 值设置为显示控件的值。
// Set focus on the selected edit control
ClientScript.RegisterStartupScript(GetType(), "SetFocus",
"<script>document.getElementById(
'" + _editControl.ClientID + "').focus();</script>");
// If the edit control is a dropdownlist set the
// SelectedValue to the value of the display control
if (_editControl is DropDownList && _displayControl is Label)
{
((DropDownList)_editControl).SelectedValue = (
(Label)_displayControl).Text;
}
// If the edit control is a textbox then select the text
if (_editControl is TextBox)
{
((TextBox)_editControl).Attributes.Add("onfocus", "this.select()");
}
// If the edit control is a checkbox set the
// Checked value to the value of the display control
if (_editControl is CheckBox && _displayControl is Label)
{
(CheckBox)_editControl).Checked = bool.Parse(((Label)_displayControl).Text);
}
在演示中,事件触发的历史记录也写到了页面上。在 RowUpdating
中,会检查行中的每个单元格是否处于编辑模式。如果找到处于编辑模式的单元格,则调用数据更新代码。
在第一个演示页面中,一些示例数据存储在一个 DataTable
中,该 DataTable
存储在 session 中。
// Loop though the columns to find a cell in edit mode
for (int i = 1; i < _gridView.Columns.Count; i++)
{
// Get the editing control for the cell
Control _editControl = _gridView.Rows[e.RowIndex].Cells[i].Controls[3];
if (_editControl.Visible)
{
.... update the data
}
}
为确保 RowUpdating
在单元格编辑后被触发,它在 Page_Load
中被调用。通过在编辑 TextBox
后按“Enter”键或点击另一个单元格,页面会回发,并进行检查以确保保存任何数据更改。
if (this.GridView1.SelectedIndex > -1)
{
this.GridView1.UpdateRow(this.GridView1.SelectedIndex, false);
}
注册用于验证的回发或回调数据
在 RowDataBound
中创建的自定义事件必须向页面注册。
ClientScriptManager.RegisterForEventValidation
是通过重写 Render
方法来调用的。
GridViewRow.UniqueID
返回行的 UniqueID
,可以通过将 "$ctl00
" 附加到行的 UniqueID
来生成按钮的 UniqueID
。
protected override void Render(HtmlTextWriter writer)
{
foreach (GridViewRow r in GridView1.Rows)
{
if (r.RowType == DataControlRowType.DataRow)
{
for (int columnIndex = _firstEditCellIndex; columnIndex <
r.Cells.Count; columnIndex++)
{
Page.ClientScript.RegisterForEventValidation(
r.UniqueID + "$ctl00", columnIndex.ToString());
}
}
}
base.Render(writer);
}
这将防止引发任何“无效的回发或回调参数”错误。
演示项目中的其他示例
使用 SQL 数据源控件编辑单个 GridView 单元格
将此技术与 SqlDataSource
控件结合使用需要对 GridView
的 RowUpdating
事件进行一些修改。SqlDataSource
控件通常在更新 GridView
行时从 EditItemTemplate
获取值来填充 NewValues
集合。
由于在此场景中未使用 EditItemTemplate
,因此必须以编程方式填充 NewValues
集合。
e.NewValues.Add(key, value);
在 App_Data 文件夹中有一个简单的 SQL Server Express 数据库用于存储数据。
(根据您的配置,您可能需要修改 web.config 中的连接字符串)。
使用对象数据源控件编辑单个 GridView 单元格
此示例使用了 App_Code 文件夹中的两个类
- Task.cs - 是
Task
对象 - TaskDataAccess.cs - 管理
Task
对象
ASPX 页面的代码隐藏与 SQL 数据源示例中的代码隐藏相同。
ObjectDataSource
通过 TaskDataAccess.cs 类中的 GetTasks
和 UpdateTask
方法来管理数据。
具有电子表格样式的 GridView
此示例有一个样式看起来像电子表格的 GridView
。
(虽然它看起来像电子表格,但它实际上并不像电子表格那样工作,毕竟它仍然是一个 GridView
!)
原理与上面相同,尽管有一些额外的代码会在单元格被点击时更改单元格样式等。

使用 SQL 数据源控件的具有电子表格样式的 GridView
此示例与上面相同,但对 GridView
的 RowUpdating
事件进行了一些修改,以使其能够与 SqlDataSource
控件一起使用。
参考文献
结论
如果您想一次编辑 ASP.NET GridView
中的一个单元格的数据,那么这种技术可能会有用。
历史
- v1.0 - 2007 年 3 月 25 日
- v2.0 - 2007 年 4 月 7 日
- 向演示项目中添加了使用
SqlDataSource
和ObjectDataSource
的示例 - v3.0 - 2007 年 11 月 23 日
- 向演示项目中添加了分页和排序的示例
- 为演示项目添加了 ASP.NET 3.5 web.config
- v4.0 - 2009 年 11 月 5 日
- 向演示项目中添加了
UpdatePanel
、验证控件和CheckBox
的示例 - 向演示项目中添加了 VB.NET 示例