GridView + UpdatePanel 实战:WebForms 无刷新增删改查与踩坑指南

发布时间:2026/10/18 9:00:08
GridView + UpdatePanel 实战:WebForms 无刷新增删改查与踩坑指南 简介这是一份针对 ASP.NET 4.0 与 SQL Server 2008 环境设计的 GridView 增删改实例主要面向正在开发 Web 信息系统的开发者解决 Visual Studio 自带列表控件交互单一、每次操作都要刷新页面的问题。资源包共 2 个文件由一个可直接打开的 htm 演示页和一份 rar 源码压缩包组成整包仅 1.52MBhtm 页面方便先查看运行效果rar 内则为核心代码与页面文件便于移植复用。已有 651 人学习下载适合初学者理解数据表格的无刷新编辑思路也适合有经验者直接抽取代码嵌入自己的项目中。此实例功能覆盖新增、删除、修改等常用操作整个交互由 Ajax 驱动不需要整页回发代码结构清晰关键逻辑集中在少量文件里稍作调整即可适配不同字段。无论用于课程设计、内部管理系统还是作为 GridView 结合 Ajax 的入门范本这份轻量资源都能提供直接有效的参考。1. 告别 GridView 刷新闪烁这套 AJAX 增删改方案能直接抄进你的 WebForms 项目手头有个内部管理系统用的 ASP.NET WebForms SQL Server列表页全靠 GridView 撑着。最早版本每次点“编辑”或者翻页整个页面都刷一遍白屏加闪烁在低配办公电脑上体验极差。后来把 GridView 和 AJAX 结合起来重构了一版无刷新增删改丝滑程度直接提升一个档次。这套方案不引入重量级前端框架底子是 GridView UpdatePanel SqlDataSource外加几个必须注意的坑。适合正在维护 WebForms 老项目、想把交互体验拉起来又不想重写成 MVC 或前后端分离的开发者。2. 为什么是 GridView UpdatePanel选型逻辑与运行机制2.1 从 PostBack 到 AJAXUpdatePanel 到底干了什么GridView 天生依赖 PostBack点一下按钮整个页面生命周期走一遍再重新渲染返回。UpdatePanel 做的事情其实很“偷懒”——它截获异步回发只把 UpdatePanel 内部区域的 HTML 替换掉而不是整页刷新。所以页面其他部分纹丝不动顶部导航、左侧菜单都不用重新加载看着就像局部更新。但要注意这里说的 AJAX 并不是传统意义上用 JavaScript 发 XMLHttpRequest而是微软的 ASP.NET AJAX 框架底层还是走 ScriptManager 那套机制。异步回发仍然会触发完整的页面生命周期只是 UI 上只刷新局部区域。理解这一点很关键后面排查 ViewState 和事件顺序问题全靠它。2.2 环境准备与最小配置新建一个 WebForms 页面必须放上 ScriptManager而且要放在 UpdatePanel 之前。这是最常见的第一步忘掉它整个异步就失效了。控件层级关系是这样asp:ScriptManager IDScriptManager1 runatserver EnablePartialRenderingtrue / asp:UpdatePanel IDUpdatePanel1 runatserver UpdateModeConditional ContentTemplate !-- GridView 和操作按钮放这里 -- /ContentTemplate /asp:UpdatePanelEnablePartialRendering默认为 true不需要额外处理。UpdateMode建议设成Conditional意思是只有内部控件触发回发时才会更新。如果不设任何按钮都可能引发整个 UpdatePanel 刷新性能上会差一些。数据库连接串放到 Web.config 里SqlDataSource 用它来做 CRUD。一个最小可用的连接串长这样connectionStrings add nameMyConn connectionStringData Sourcelocalhost;Initial CatalogMyDB;User IDsa;PasswordYourPassword; providerNameSystem.Data.SqlClient / /connectionStrings实际部署时密码要放到配置加密里别硬编码。开发环境可以临时这样写上生产必须改。3. GridView 核心配置绑定、分页与排序的实战参数3.1 SqlDataSource 的四个命令参数要实现增删改查SqlDataSource 需要同时配好SelectCommand、InsertCommand、UpdateCommand、DeleteCommand四个命令。参数来自 GridView 的数据键DataKeyNames这个名字必须和主键字段完全一致大小写也不能差。asp:SqlDataSource IDsdsData runatserver ConnectionString%$ ConnectionStrings:MyConn % SelectCommandSELECT [ID], [Name], [Age], [Dept], [CreateTime] FROM [Users] ORDER BY [CreateTime] DESC InsertCommandINSERT INTO [Users]([Name],[Age],[Dept],[CreateTime]) VALUES (Name,Age,Dept,CreateTime) UpdateCommandUPDATE [Users] SET [Name]Name,[Age]Age,[Dept]Dept WHERE [ID]ID DeleteCommandDELETE FROM [Users] WHERE [ID]ID InsertParameters asp:Parameter NameName TypeString / asp:Parameter NameAge TypeInt32 / asp:Parameter NameDept TypeString / asp:Parameter NameCreateTime TypeDateTime / /InsertParameters /asp:SqlDataSource逻辑说明SelectCommand里用了ORDER BY CreateTime DESC保证最新数据排最前。插入和更新参数来自 GridView 模板里的文本框或下拉框名字要和参数名对应。主键 ID 不用出现在 Insert 语句里那是自增列。DataKeyNamesID是必须的否则更新和删除时找不到行。3.2 让分页和排序不打断 AJAX 无刷新体验GridView 自带分页和排序但默认行为是整页回发。在 UpdatePanel 里只要把这几项设对分页和排序也会自动变成无刷新asp:GridView IDgvUsers runatserver DataSourceIDsdsData DataKeyNamesID AllowPagingTrue PageSize10 AllowSortingTrue AutoGenerateColumnsFalse OnRowCommandgvUsers_RowCommand OnRowEditinggvUsers_RowEditing OnRowUpdatinggvUsers_RowUpdating OnRowCancelingEditgvUsers_RowCancelingEdit OnRowDeletinggvUsers_RowDeleting /asp:GridView常见参数爬坑点AutoGenerateColumns必须设成 False绑定的列名才可控。PageSize别设太大10 到 15 是比较舒服的范围。AllowSorting打开后表头会自动出现可点击的排序链接配合SortExpression指定每个列的排序字段。凡是绑定的列都要设置SortExpression否则点击该列表头会报错。模板列里要放编辑和删除按钮asp:TemplateField HeaderText操作 ItemTemplate asp:Button IDbtnEdit runatserver Text编辑 CommandNameEdit / asp:Button IDbtnDelete runatserver Text删除 CommandNameDelete OnClientClickreturn confirm(确定删除这条记录吗); / /ItemTemplate /asp:TemplateFieldCommandNameEdit是 GridView 内置的编辑命令不用额外写代码就会自动进入编辑状态。删除按钮加了OnClientClick弹确认框这是最省事的做法。4. 增删改的完整落地从模板列到事件处理的联动4.1 编辑状态下的模板列与 OnRowUpdating 处理GridView 进入编辑状态后模板列会切换成EditItemTemplate。这里通常放 TextBox 或 DropDownList用来接收用户输入。关键点是这些控件的 ID 要和后端取值时保持一致写法上习惯用FindControl定位。asp:TemplateField HeaderText姓名 SortExpressionName ItemTemplate %# Eval(Name) % /ItemTemplate EditItemTemplate asp:TextBox IDtxtName runatserver Text%# Bind(Name) % / /EditItemTemplate /asp:TemplateField这里的Bind(Name)比Eval(Name)更重要。编辑状态下必须用Bind因为Bind支持双向绑定可以让 SqlDataSource 的更新命令自动拿到这个值。用Eval只能显示更新时拿不到新数据。事件处理代码写在页面的 code-behind 里protected void gvUsers_RowUpdating(object sender, GridViewUpdateEventArgs e) { GridViewRow row gvUsers.Rows[e.RowIndex]; TextBox txtName (TextBox)row.FindControl(txtName); // 可以根据需要修改 e.NewValues或者做自定义验证 if (string.IsNullOrEmpty(txtName.Text)) { e.Cancel true; // 这里可以显示一个提示比如放在 UpdatePanel 里的 Label } }这段逻辑说明e.RowIndex是当前编辑行的索引FindControl根据 ID 找到模板里的文本框。如果需要做服务端校验在这里判断并设置e.Cancel true取消本次更新。注意校验规则要和前端确认框区分开前端是提示用户确认这里是拦截无效数据。4.2 新增功能借助 FooterTemplate 实现快速插入GridView 本身没有内置的新增模板。常用方案是在页面底部放一个 FormView或者把新增字段放在 GridView 上方的独立区域。更优雅的做法是利用FooterTemplate把新增表单藏在表格底部asp:TemplateField HeaderText新增记录 FooterTemplate asp:TextBox IDtxtNewName runatserver Placeholder姓名 / asp:TextBox IDtxtNewAge runatserver Placeholder年龄 / asp:Button IDbtnInsert runatserver Text新增 CommandNameInsert / /FooterTemplate /asp:TemplateField在OnRowCommand里捕捉插入命令protected void gvUsers_RowCommand(object sender, GridViewCommandEventArgs e) { if (e.CommandName Insert) { GridViewRow footer gvUsers.FooterRow; TextBox txtName (TextBox)footer.FindControl(txtNewName); TextBox txtAge (TextBox)footer.FindControl(txtNewAge); // 把值塞给 SqlDataSource 的 InsertParameters sdsData.InsertParameters[Name].DefaultValue txtName.Text; sdsData.InsertParameters[Age].DefaultValue txtAge.Text; sdsData.Insert(); // 刷新 GridView gvUsers.DataBind(); } }常见做法是点新增按钮后先做非空检查没填就提示并 return。sdsData.Insert()会触发 SqlDataSource 的InsertCommand参数值来自InsertParameters。这里的DefaultValue看起来像字符串框架会按 Parameter 配置的类型自动转换Age 是 Int32 就会自动转成整数。4.3 删除操作的二次确认与服务器端兜底前端确认框只防君子不防小人。服务器端还要再判断一次防止跨站请求伪造或者前端脚本绕过protected void gvUsers_RowDeleting(object sender, GridViewDeleteEventArgs e) { if (Session[UserRole] null || Session[UserRole].ToString() ! Admin) { e.Cancel true; // 这里可以提示无权限 } }这里用 Session 做权限校验属于最简单的做法真实项目里通常会走 FormsAuthentication 或自定义的权限服务。意义在于权限校验必须在服务器端执行前端确认框只是体验优化。数据库报异常的情况也要处理比如外键约束导致的删除失败需要在OnRowDeleted里判断e.Exception。5. AJAX 与 GridView 搭配的常见坑现象、原因、解决方案5.1 点击编辑后整个页面还是刷了UpdatePanel 没生效现象GridView 在 UpdatePanel 里但点按钮后浏览器还是全屏加载地址栏没变化状态栏闪现进度条。原因GridView 的某些内置控件比如LinkButton在数据绑定后注册的回发脚本和 UpdatePanel 冲突。另一个可能是 ScriptManager 没有出现在 UpdatePanel 之前或者页面里存在多个 ScriptManager。解决把 ScriptManager 放在页面顶部且在 UpdatePanel 外。检查是否只有一个 ScriptManager。如果用了母版页母版页里放了 ScriptManager内容页就不要再放。还有就是把ClientIDMode设为Static有可能会干扰脚本生成优先保持默认。5.2 ViewState 在异步回发中被撑爆现象页面打开要 3 秒无刷新后再次操作越来越慢最后可能直接偶发 js 错误。原因GridView 数据量一大ViewState 全埋在隐藏字段里。每次异步回发这个字段都要来回传一遍重复累计。解决给 SqlDataSource 和 GridView 双重限制EnableViewStateFalse放到 GridView 上。但是考虑到编辑状态需要保存行状态直接把 ViewState 关掉会导致编辑模板状态丢失。折中方案是开启数据库存储 Session 来承载 ViewState设置pages节点的viewStateModeEnabled但配合SessionPageStatePersister。或者是限制PageSize20 行以内基本够用。5.3 日期时间字段在 Insert 时报错现象文本框里输入2024/05/01SqlDataSource 插入时报字符串转 DateTime 失败。原因连接串和数据库文化设置不匹配浏览器本地日期格式是yyyy/MM/dd但 SQL Server 默认yyyy-MM-dd。解决在 InsertParameters 里显式指定TypeDateTime同时文本框给一个Cultureen-US的格式化。更稳妥的方法是服务端先解析DateTime dt; if (DateTime.TryParse(txtDate.Text, out dt)) { sdsData.InsertParameters[CreateTime].DefaultValue dt.ToString(yyyy-MM-dd HH:mm:ss); }TryParse失败时默认值是DateTime.MinValue所以要先判断。只要日期字段存在就统一走服务端格式化不要依赖前端 value。5.4 UpdatePanel 里的绑定事件连续触发两次现象点击“保存”按钮数据库里插入两条一样的记录。原因按钮同时在 GridView 行内和页面底部绑定了事件或者OnRowCommand里同时接住了按钮回发和控件默认命令。解决检查所有 Button 的CommandName是否有重复。GridView 行的“更新”会同时触发RowUpdating和RowCommand如果RowCommand里又写了Update分支就会重复执行。规范是RowUpdating、RowDeleting只处理数据操作RowCommand只处理自定义命令。5.5 排序后编辑按钮失效点击没反应现象点表头排序列表变了但再点“编辑”按钮没有任何反应。原因排序执行后 GridView 重新绑定行索引变了但 DataKeyNames 的缓存没刷新或者排序和编辑事件在 PostBack 中的触发顺序不对。解决在排序事件OnSorting里先调用gvUsers.DataBind()强制刷新数据源然后在OnDataBound里恢复一下当前编辑状态。最保险的做法是关闭排序状态在 ViewState 中的保存每次排序后自动回到第一页。这种问题在 UpdatePanel 里特别容易踩到因为排序和编辑都会触发异步回发但回发数据是分段重放的。6. 把无刷新体验再往前推一步WebMethod 模式与前端提示联动UpdatePanel 方案够用但如果你觉得一个页面里放五六个 UpdatePanel 还是太重可以换一种混合模式GridView 保留服务端渲染但增删改用 WebMethod 走纯 AJAX 接口。好处是数据库操作不需要完整走一遍页面生命周期代码更轻前端交互更灵活。具体做法是给页面加一个静态方法标记[WebMethod]然后在 JavaScript 里用PageMethods调用[System.Web.Services.WebMethod] public static bool DeleteUser(int userID) { string conn ConfigurationManager.ConnectionStrings[MyConn].ConnectionString; using (SqlConnection cn new SqlConnection(conn)) { using (SqlCommand cmd new SqlCommand(DELETE FROM Users WHERE IDID, cn)) { cmd.Parameters.AddWithValue(ID, userID); cn.Open(); return cmd.ExecuteNonQuery() 0; } } }前端用 jQuery 或者原生 XMLHttpRequest 调这个接口删除成功后在前端把这一行淡出再移除不触发任何 PostBack。这种方式反过来要求 GridView 的每一行都放一个>tr>$(document).on(click, .btn-ajax-delete, function () { var id $(this).closest(tr).attr(data-id); if (confirm(确认删除)) { PageMethods.DeleteUser(id, function (result) { if (result) { // 页面表格局部刷新或直接移除当前行 } }); } });这套模式适合数据量中等、操作频繁的内部系统但它绕过了 SqlDataSource 的自动命令SQL 语句需要手写。维护成本比 UpdatePanel 高换来的响应速度更快也不会因为 ViewState 变大拖慢回发。验证方案在浏览器开发者工具的 Network 面板里UpdatePanel 模式请求类型是异步回发的脚本负载返回的是更新区域的 HTMLWebMethod 模式返回的是 JSON直接能看到结构和响应时间。用哪种模式取决于你对现有代码的改动预算UpdatePanel 改动最小WebMethod 灵活度更高。我在实际项目里是把两种模式混着用的——列表展示和分页排序走 UpdatePanel删除和快速批量操作走 WebMethod这样既保住了 GridView 的成熟功能又把操作体验提起来了。从那以后我每次接 WebForms 老项目都会先问清楚列表操作频率再决定用哪套方案强制在动工前把交互路径画清楚。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询