.NET 4.7 WebForms无数据库GridView做CRUD报RowUpdating事件未处理错误
问题根因
这个报错的核心原因是GridView事件绑定模式和实现逻辑不匹配:
- 你配置的
UpdateMethod是ASP.NET 4.5引入的强类型Model Binding模式专属属性,仅在通过SelectMethod配置数据源查询方法时才会自动触发 - 你当前使用的是手动赋值
DataSource+调用DataBind()的传统绑定模式,这种模式下点击更新按钮时,GridView会直接触发RowUpdating行事件,你没有绑定对应的OnRowUpdating事件处理方法,就会抛出“事件未处理”的错误。
现有代码还存在几个会导致CRUD功能失效的问题:
- 未给GridView配置
DataKeyNames属性指定主键字段,更新、删除时无法获取行对应的主键值 GView_RowEditing事件方法为空,没有实际执行切换编辑索引、重新绑定数据的逻辑- 未绑定
RowCancelingEdit(取消编辑)、RowDeleting(删除)事件,点击对应按钮时也会抛出同类未处理事件错误 Page_Load没有处理首次加载的数据绑定逻辑,内存数据无法正常加载到控件
修复方案1:传统绑定模式(改造成本最低)
不需要改动现有内存List存储逻辑,补全事件绑定和对应处理方法即可。
- 修改前端GridView控件配置,补全事件绑定、主键配置,移除无效的
UpdateMethod属性:
<asp:GridView runat="server" ID="GView" CellPadding="4" ForeColor="#333333" GridLines="None" DataKeyNames="Id" OnRowEditing="GView_RowEditing" OnRowCancelingEdit="GView_RowCancelingEdit" OnRowUpdating="GView_RowUpdating" OnRowDeleting="GView_RowDeleting" AutoGenerateColumns="True"> <AlternatingRowStyle BackColor="White"></AlternatingRowStyle> <Columns> <asp:CommandField ShowEditButton="True" ShowDeleteButton="True"></asp:CommandField> </Columns> </asp:GridView>
- 补全后端事件逻辑,修正数据绑定逻辑:
protected void Page_Load(object sender, EventArgs e) { // 仅首次页面加载时绑定数据,回发场景不重复绑定,避免覆盖编辑状态 if (!IsPostBack) { BindGrid(); } } // 抽离统一绑定方法,减少重复代码 private void BindGrid() { GView.DataSource = contatos; GView.DataBind(); } public static List<Contato> contatos = new List<Contato>(); public void btnCad(object sender, EventArgs e) { Contato contato = new Contato(); // 注意:用Count作为自增Id在删除数据后会出现Id重复问题,仅适合测试场景 contato.Id = contatos.Count; contato.Nome = this.txtNome.Text; contato.Idade = this.txtIdade.Text; contato.Telefone = this.txtTelefone.Text; contato.Genero = this.txtGenero.Text; contato.DataCadastro = this.txtDataCad.Text; contatos.Add(contato); BindGrid(); } // 切换行编辑状态 protected void GView_RowEditing(object sender, GridViewEditEventArgs e) { GView.EditIndex = e.NewEditIndex; BindGrid(); } // 取消编辑 protected void GView_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e) { GView.EditIndex = -1; BindGrid(); } // 处理更新逻辑 protected void GView_RowUpdating(object sender, GridViewUpdateEventArgs e) { // 从DataKey中获取当前行主键 int id = Convert.ToInt32(GView.DataKeys[e.RowIndex].Value); Contato item = contatos.Find(cont => cont.Id == id); if (item == null) return; // 从编辑行的输入控件中取新值,注意单元格索引按实际列顺序调整:前两列为命令按钮列,业务字段从第3列(索引2)开始 item.Nome = (GView.Rows[e.RowIndex].Cells[2].Controls[0] as TextBox)?.Text; item.Idade = (GView.Rows[e.RowIndex].Cells[3].Controls[0] as TextBox)?.Text; item.Telefone = (GView.Rows[e.RowIndex].Cells[4].Controls[0] as TextBox)?.Text; item.Genero = (GView.Rows[e.RowIndex].Cells[5].Controls[0] as TextBox)?.Text; item.DataCadastro = (GView.Rows[e.RowIndex].Cells[6].Controls[0] as TextBox)?.Text; // 退出编辑状态,刷新数据 GView.EditIndex = -1; BindGrid(); } // 处理删除逻辑 protected void GView_RowDeleting(object sender, GridViewDeleteEventArgs e) { int id = Convert.ToInt32(GView.DataKeys[e.RowIndex].Value); Contato item = contatos.Find(cont => cont.Id == id); if (item != null) { contatos.Remove(item); } BindGrid(); }
修复方案2:Model Binding模式(适配原有UpdateMethod写法)
如果要使用你之前写的UpdateMethod、TryUpdateModel的简化写法,就用Model Binding模式,不需要手动从单元格取控件值。
- 修改前端GridView配置,补全绑定方法配置:
<asp:GridView runat="server" ID="GView" CellPadding="4" ForeColor="#333333" GridLines="None" DataKeyNames="Id" SelectMethod="GView_GetData" UpdateMethod="GView_UpdateItem" DeleteMethod="GView_DeleteItem" AutoGenerateColumns="True"> <AlternatingRowStyle BackColor="White"></AlternatingRowStyle> <Columns> <asp:CommandField ShowEditButton="True" ShowDeleteButton="True"></asp:CommandField> </Columns> </asp:GridView>
- 后端实现对应绑定方法,不需要手动调用
DataBind:
protected void Page_Load(object sender, EventArgs e) { // Model Binding模式自动处理数据绑定,不需要手动写绑定逻辑 } public static List<Contato> contatos = new List<Contato>(); // SelectMethod:返回GridView需要绑定的全量数据 public List<Contato> GView_GetData() { return contatos; } public void btnCad(object sender, EventArgs e) { Contato contato = new Contato(); contato.Id = contatos.Count; contato.Nome = this.txtNome.Text; contato.Idade = this.txtIdade.Text; contato.Telefone = this.txtTelefone.Text; contato.Genero = this.txtGenero.Text; contato.DataCadastro = this.txtDataCad.Text; contatos.Add(contato); } // 原有更新方法可直接生效,TryUpdateModel自动完成输入值到实体的映射 public void GView_UpdateItem(int id) { Contato item = contatos.Find(cont => cont.Id == id); if (item == null) { ModelState.AddModelError("", String.Format("O item com id {0} não foi encontrado", id)); return; } TryUpdateModel(item); if (ModelState.IsValid) { // 更新成功后控件自动刷新数据,不需要手动绑定 } } // 删除方法 public void GView_DeleteItem(int id) { Contato item = contatos.Find(cont => cont.Id == id); if (item != null) { contatos.Remove(item); } }
注意:使用
static List<Contato>存储数据时,所有访问站点的用户会共享同一份数据,且应用程序池重启后数据会全部丢失,仅适合本地功能测试,不能直接用于生产环境。
内容的提问来源于stack exchange,提问作者lucasmenchon
相关产品推荐
相关产品推荐

