如何使用C#对ASP GridView执行自定义CRUD操作
ASP.NET Web Forms 中使用C#实现GridView自定义CRUD操作
不需要依赖SqlDataSource、ObjectDataSource等数据源控件的内置CRUD能力,所有交互逻辑完全自定义,适配个性化业务规则。
基础配置要求
- 页面GridView必须设置
DataKeyNames属性为对应数据表的主键字段名(比如DataKeyNames="Id"),用于增删改时精准定位记录,避免前端传参被篡改 - 关闭
AutoGenerateColumns="false",所有列通过BoundField或TemplateField自定义 - 页面默认开启ViewState,否则回发时GridView状态、编辑态会丢失
前端页面(.aspx)示例代码
<asp:GridView ID="gvData" runat="server" AutoGenerateColumns="False" DataKeyNames="Id" OnRowCommand="gvData_RowCommand" OnRowEditing="gvData_RowEditing" OnRowCancelingEdit="gvData_RowCancelingEdit" OnRowUpdating="gvData_RowUpdating" OnRowDeleting="gvData_RowDeleting" ShowFooter="true"> <Columns> <asp:TemplateField HeaderText="名称"> <ItemTemplate><%# Eval("Name") %></ItemTemplate> <EditItemTemplate> <asp:TextBox ID="txtEditName" runat="server" Text='<%# Bind("Name") %>'></asp:TextBox> </EditItemTemplate> <FooterTemplate> <asp:TextBox ID="txtAddName" runat="server"></asp:TextBox> </FooterTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="描述"> <ItemTemplate><%# Eval("Description") %></ItemTemplate> <EditItemTemplate> <asp:TextBox ID="txtEditDesc" runat="server" Text='<%# Bind("Description") %>' TextMode="MultiLine"></asp:TextBox> </EditItemTemplate> <FooterTemplate> <asp:TextBox ID="txtAddDesc" runat="server" TextMode="MultiLine"></asp:TextBox> </FooterTemplate> </asp:TemplateField> <asp:CommandField ShowEditButton="True" ShowDeleteButton="True" CancelText="取消" EditText="编辑" UpdateText="更新" DeleteText="删除" /> <asp:TemplateField> <FooterTemplate> <asp:Button ID="btnAdd" runat="server" Text="新增记录" CommandName="AddNew" /> </FooterTemplate> </asp:TemplateField> </Columns> </asp:GridView>
后置C#代码(.aspx.cs)
首先写通用的数据绑定方法,所有操作完成后都调用这个方法刷新数据:
private string connStr = ConfigurationManager.ConnectionStrings["DbConn"].ConnectionString; private void BindGrid() { using(SqlConnection conn = new SqlConnection(connStr)) { string sql = "SELECT Id,Name,Description FROM TestTable ORDER BY Id DESC"; SqlDataAdapter sda = new SqlDataAdapter(sql, conn); DataTable dt = new DataTable(); sda.Fill(dt); gvData.DataSource = dt; gvData.DataBind(); } } protected void Page_Load(object sender, EventArgs e) { if(!IsPostBack) { BindGrid(); } }
逐个实现事件逻辑:
// 处理行级自定义命令(这里处理新增逻辑) protected void gvData_RowCommand(object sender, GridViewCommandEventArgs e) { if(e.CommandName == "AddNew") { // 取页脚新增输入框的值 GridViewRow footerRow = gvData.FooterRow; string name = (footerRow.FindControl("txtAddName") as TextBox).Text.Trim(); string desc = (footerRow.FindControl("txtAddDesc") as TextBox).Text.Trim(); // 这里可以加自定义业务校验,比如非空判断 if(string.IsNullOrEmpty(name)) { ClientScript.RegisterStartupScript(this.GetType(), "tip", "alert('名称不能为空');", true); return; } // 参数化执行插入 using(SqlConnection conn = new SqlConnection(connStr)) { string sql = "INSERT INTO TestTable(Name,Description) VALUES(@Name,@Desc)"; SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddWithValue("@Name", name); cmd.Parameters.AddWithValue("@Desc", desc); conn.Open(); cmd.ExecuteNonQuery(); } // 操作完重新绑定 BindGrid(); } } // 切换到编辑态 protected void gvData_RowEditing(object sender, GridViewEditEventArgs e) { gvData.EditIndex = e.NewEditIndex; BindGrid(); } // 取消编辑 protected void gvData_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e) { gvData.EditIndex = -1; BindGrid(); } // 更新编辑数据 protected void gvData_RowUpdating(object sender, GridViewUpdateEventArgs e) { // 从DataKey取主键,避免前端篡改 int id = Convert.ToInt32(gvData.DataKeys[e.RowIndex].Value); GridViewRow editRow = gvData.Rows[e.RowIndex]; string newName = (editRow.FindControl("txtEditName") as TextBox).Text.Trim(); string newDesc = (editRow.FindControl("txtEditDesc") as TextBox).Text.Trim(); // 自定义校验逻辑 if(string.IsNullOrEmpty(newName)) { ClientScript.RegisterStartupScript(this.GetType(), "tip", "alert('名称不能为空');", true); return; } // 参数化更新 using(SqlConnection conn = new SqlConnection(connStr)) { string sql = "UPDATE TestTable SET Name=@Name,Description=@Desc WHERE Id=@Id"; SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddWithValue("@Name", newName); cmd.Parameters.AddWithValue("@Desc", newDesc); cmd.Parameters.AddWithValue("@Id", id); conn.Open(); cmd.ExecuteNonQuery(); } // 退出编辑态,重新绑定 gvData.EditIndex = -1; BindGrid(); } // 删除记录 protected void gvData_RowDeleting(object sender, GridViewDeleteEventArgs e) { int id = Convert.ToInt32(gvData.DataKeys[e.RowIndex].Value); // 可以加删除前校验,比如判断记录有没有关联数据 using(SqlConnection conn = new SqlConnection(connStr)) { string sql = "DELETE FROM TestTable WHERE Id=@Id"; SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddWithValue("@Id", id); conn.Open(); cmd.ExecuteNonQuery(); } BindGrid(); }
注意:所有数据库操作必须使用参数化查询,禁止直接拼接SQL字符串,否则存在SQL注入风险。
个性化扩展方向
- 无刷新交互:将GridView包裹在
UpdatePanel控件内,搭配ScriptManager即可实现局部回发,避免整页刷新 - 权限控制:在
RowDataBound事件中根据当前登录用户的权限,动态隐藏编辑、删除按钮,无权限用户看不到操作入口 - 复杂表单支持:编辑项、新增项模板里可以替换成DropDownList、CheckBox、日期选择器等控件,只要在对应事件里用FindControl找到控件取值即可
- 批量操作:新增复选框模板列,加批量删除、批量修改按钮,在RowCommand里遍历选中行批量执行SQL即可
常见踩坑点
- 所有增删改操作执行完成后必须调用
BindGrid()重新绑定数据,否则界面不会显示最新数据 - 模板列的控件取值必须用
FindControl()方法,不要直接通过Cells[i].Text取值,模板列的单元格Text属性默认是空值 - 不要把主键值放在前端隐藏域或者单元格里传递,统一通过
DataKeys集合取,避免用户篡改前端参数越权操作其他记录
内容的提问来源于stack exchange,提问作者Odel Mhande
相关产品推荐
相关产品推荐

