65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (80投票s)

2007年3月25日

CPOL

5分钟阅读

viewsIcon

1419575

downloadIcon

26356

在不将整行置于编辑模式的情况下,编辑单个 GridView 单元格。示例包含使用 SqlDataSource 和 ObjectDataSource 控件。

引言

ASP.NET 的 GridView 通过设置 GridViewEditIndex 属性,可以将整行数据置于编辑模式进行编辑。

如果您正在为 EditItemTemplate 中的多个列使用 DropDownList 控件,您可能不希望将整行都置于编辑模式。如果每个 DropDownList 都有很多选项,一次性加载所有选项可能会导致页面响应缓慢。此外,如果您的数据结构更像一个二维数组而不是一组行,您可能希望单独编辑每个单元格。

在这里,我将演示如何实现这一点,以及如何处理 Event Validation 而无需禁用它。

背景

本文基于我之前一篇博文的读者提问:ASP.NET 中 GridView 和 DataList 控件的可点击和双击行

要理解使 GridView 行可点击的概念,您可能希望在继续之前阅读它。

编辑单个 GridView 单元格

Screenshot - EditGridviewCells1.jpg

演示中的 GridView 在第一列有一个名为 SingleClickasp:ButtonField 控件,其可见性设置为 false

这用于向 GridView 行添加点击事件。

<Columns>
    <asp:ButtonField Text="SingleClick" CommandName="SingleClick"
                        Visible="False" />
</Columns>

对于其他列,都有一个带有可见 Label 控件和不可见 TextBoxDropdownListCheckBox 控件的项模板。

为了方便起见,我们将 Label 称为“显示控件”,将 TextBoxDropdownListCheckBox 称为“编辑控件”。

<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,编辑控件的可见性设置为 trueEditItemTemplate 未被使用。

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 控件结合使用需要对 GridViewRowUpdating 事件进行一些修改。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 类中的 GetTasksUpdateTask 方法来管理数据。

具有电子表格样式的 GridView

此示例有一个样式看起来像电子表格的 GridView

(虽然它看起来像电子表格,但它实际上并不像电子表格那样工作,毕竟它仍然是一个 GridView!)

原理与上面相同,尽管有一些额外的代码会在单元格被点击时更改单元格样式等。

Screenshot - EditGridviewCells2.jpg

使用 SQL 数据源控件的具有电子表格样式的 GridView

此示例与上面相同,但对 GridViewRowUpdating 事件进行了一些修改,以使其能够与 SqlDataSource 控件一起使用。

参考文献

结论

如果您想一次编辑 ASP.NET GridView 中的一个单元格的数据,那么这种技术可能会有用。

历史

  • v1.0 - 2007 年 3 月 25 日
  • v2.0 - 2007 年 4 月 7 日
    • 向演示项目中添加了使用 SqlDataSourceObjectDataSource 的示例
  • v3.0 - 2007 年 11 月 23 日
    • 向演示项目中添加了分页和排序的示例
    • 为演示项目添加了 ASP.NET 3.5 web.config
  • v4.0 - 2009 年 11 月 5 日
    • 向演示项目中添加了 UpdatePanel、验证控件和 CheckBox 的示例
    • 向演示项目中添加了 VB.NET 示例
© . All rights reserved.