news 2026/9/8 6:05:56

ASP.NET GridView与AJAX实战:从UpdatePanel到jQuery的完整方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ASP.NET GridView与AJAX实战:从UpdatePanel到jQuery的完整方案

简介:这是一份面向ASP.NET开发者的GridView操作实例,基于ASP.NET 4.0与SQL Server 2008环境构建,重点解决自带GridView在数据增删改操作中页面频繁刷新、交互反馈生硬的问题,适用于后台管理模块、信息发布系统等需要快速搭建表格页面的场景。作者从国外技术论坛筛选出该实用方案,代码结构清晰,完整涵盖新增、编辑、删除三项核心功能,并采用Ajax实现无刷新交互,大幅提升操作流畅度;同时示例可移植性强,稍作调整即可融入现有项目,对初中级开发人员尤其友好。资源包共2个文件,包括1个htm页面文件和1个rar源码压缩包,整体大小约1.52MB;其中htm文件主要用于预览运行效果或说明用法,rar包内则包含可直接参考的完整代码,便于对照学习与实际复用。该资源目前已吸引649人浏览学习,在同类GridView示例中属于轻量而实用的收藏级内容。通过这份实例,读者可以掌握ASP.NET中GridView结合Ajax进行数据增删改的实现思路,理解前后台事件绑定与数据库操作的配合方式,并借助现有模板扩展字段和样式,有效缩短后台管理页面的开发周期。

1. GridView为何能成为ASP.NET的"生产力担当"

1.1 从一次内部系统开发说起

去年我在帮一家制造企业做设备资产管理系统时,遇到了一个很典型的需求:设备台账页面上,需要把几百条记录分页展示,支持按部门筛选、按状态着色,还要能一键导出。按理说这种需求在很多前端框架里都能实现,但客户那边是老牌的ASP.NET WebForms环境,开发周期只有两周。我第一时间想到的,就是把GridView拿出来用。

GridView是ASP.NET里最老牌的数据绑定控件之一。它的核心价值在于:你不需要手动拼接HTML表格,不需要写复杂的循环渲染逻辑,只要给它绑定一个数据源,设置好列字段,它就能自动生成完整的表格结构,还自带分页、排序、编辑、删除这些基础交互。对于企业内部系统、后台管理面板这种"表格密集型"项目,这东西省下的时间不是一星半点。

说实话,这些年我见过不少开发者在技术选型时一听到WebForms就皱眉,觉得它老、笨重、控件封装过度。但实际经历过大型项目的人心里都清楚,GridView在处理标准CRUD场景时的效率,依然很难被替代。尤其是配上AJAX无刷新效果之后,用户体验和交互流畅度完全能跟上现代前端的水准。

1.2 必须搞懂的几个基础属性

要真正用好GridView,有几个属性是绕不开的。首先是AutoGenerateColumns,默认值是true,意思是自动根据数据源的字段生成列。开发阶段这样确实省事,但到了生产环境我强烈建议把它设置为false,手动声明每个列。原因很简单:一旦数据源字段顺序变化,或者你只想展示其中几个字段,自动生成列会完全失控。

其次是DataKeyNames。这玩意儿很多人容易忽略,但它直接决定了编辑和删除功能能不能正常工作。GridView的行操作(如RowEditingRowDeleting)默认需要通过主键来识别具体是哪一行,而DataKeyNames就是用来指定这个主键字段的。我之前碰到过有同事没设置这个属性,点击删除按钮之后后台怎么都拿不到行ID,排查了半天才意识到是这个小问题。

再就是OnRowCommand事件。如果你在模板列里放了自定义按钮,比如"详情""审批"这种不在GridView默认操作里的按钮,RowCommand事件就是你的主要入口。通过e.CommandArgument可以拿到当前行的主键值,再配合CommandName来判断具体点了哪个按钮。这套机制一旦用熟了,你就能在GridView上实现各种业务操作,而不只是简单的增删改查。

2. 给GridView装上AJAX引擎:UpdatePanel实战方案

2.1 UpdatePanel实现无刷新排序、分页

说到GridView的AJAX效果,很多初学者第一反应是用jQuery的$.ajax去请求服务端接口,然后手动拼接HTML。这个思路本身没错,但在WebForms环境里,一个更高效的做法是使用UpdatePanel。这是ASP.NET AJAX扩展提供的一个控件,它的设计理念是"局部回发"——整个页面不刷新,只更新指定区域的DOM内容。

我用一个实际例子来说明。假设页面上有一个GridView显示订单列表,开启了排序和分页功能:

<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional"> <ContentTemplate> <asp:GridView ID="gvOrders" runat="server" AutoGenerateColumns="false" DataKeyNames="OrderID" AllowPaging="true" PageSize="10" AllowSorting="true" OnPageIndexChanging="gvOrders_PageIndexChanging" OnSorting="gvOrders_Sorting"> <Columns> <asp:BoundField DataField="OrderID" HeaderText="订单号" SortExpression="OrderID" /> <asp:BoundField DataField="CustomerName" HeaderText="客户名称" SortExpression="CustomerName" /> <asp:BoundField DataField="TotalAmount" HeaderText="订单金额" /> <asp:BoundField DataField="CreateTime" HeaderText="下单时间" /> </Columns> </asp:GridView> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="btnRefresh" EventName="Click" /> </Triggers> </asp:UpdatePanel>

关键在于后台代码里,分页和排序处理事件照常写,只是在数据绑定前判断一下IsPostBack就行。当用户点击下一页或者列标题进行排序时,页面不会整个刷新,只有GridView所在的区域更新。这个过程对用户来说几乎是瞬间完成的,体感上跟你用Vue、React这些前端框架做局部刷新没什么区别。

2.2 为什么UpdatePanel比纯前端方案更省心

我知道有些读者会问:放着现成的AJAX不用,非要用UpdatePanel这种"老古董"技术做什么?我的回答是:要看场景。

如果项目已经是Asp.NET WebForms架构,后端逻辑大量依赖服务端控件的事件模型,比如RowDataBoundRowEditingItemUpdating这些生命周期事件,那用UpdatePanel是最平滑的升级路径。你不需要改任何后端的业务逻辑,只在页面外层包一个UpdatePanel,就能获得无刷新的交互体验。这相当于给老项目做"微创手术",风险低、见效快。

而如果强行引入前端框架,比如Vue或者React,那你就得在服务端设计一套完整的Web API,把原有的服务端控件事件全部转换成JSON接口调用,再在前端重新实现表格渲染、分页逻辑、校验逻辑。这不是不行,但工作量是指数级上升的,而且很容易在接口调试、跨域、序列化等环节踩坑。对于企业内部系统来说,投入产出比完全不成正比。

我之前做过一个对比测试:同样一个订单管理页面,用UpdatePanel改造大约花了两小时,用Vue重写花了整整两天。而且前者在IE和旧版Edge上的兼容性完全没问题,后者还得考虑polyfill。不是说前端方案不好,而是说工具要匹配场景。

3. 进阶玩法:JSON交互与自定义数据绑定

3.1 用jQuery发AJAX请求,把数据喂给GridView

UpdatePanel解决的是"服务端控件自身的异步刷新",但在实际项目中,我们经常需要与第三方接口或自定义业务逻辑交互,这时候还是要用原生的AJAX方式。

举一个我实际做过案例:设备管理系统中,前端页面需要根据用户选择的部门,异步获取该部门下的设备列表,然后展示在GridView中。方案是:前端用jQuery发起GET请求,服务端返回JSON数据,前端遍历JSON并动态拼接GridView需要的HTML结构。

服务端的一个精简ASP.NET WebMethod示例:

[WebMethod] public static string GetDeviceList(string deptId) { DataTable dt = GetDeviceDataFromDb(deptId); string json = JsonConvert.SerializeObject(dt, new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" }); return json; }

这里有一个细节值得说道说道:如果直接对DataTable进行序列化,DateTime字段默认会变成类似\/Date(1640966400000)\/这样的格式,极难阅读。加一个IsoDateTimeConverter,就能保证前端拿到的是标准格式的时间字符串。这种细节点,文档里很少会写清楚,但实际开发中几乎必然会遇到。

前端处理返回的数据也不难。拿到JSON数组之后,用原生JavaScript或者jQuery拼接出表格行,然后渲染到目标容器中。这个方案的灵活性比UpdatePanel高很多,适合那些数据结构不固定、需要在前端做高度定制化展示的场景。

3.2 服务端从Request.Body读取JSON参数的写法

很多开发者在做AJAX请求时,习惯用application/x-www-form-urlencoded这种方式传参,然后在后台用Request.Form["key"]来取值。但如果前端项目用的是application/json格式,这个时候Request.Form就取不到值了,你需要在后台读取Request.Body

热词里提到的StreamReader(HttpContext.Request.Body),正是处理这种情况的标准写法。我在一个Web API的项目里就踩过这个坑。前端的AJAX请求这样写:

$.ajax({ url: "/api/device/save", type: "POST", data: JSON.stringify({ deviceCode: "DEV001", deviceName: "注塑机", status: 2 }), contentType: "application/json; charset=utf-8", dataType: "json", success: function (res) { // 处理结果 } });

如果后台是这样取值,就会取不到任何数据:

string deviceCode = Request.Form["deviceCode"];

正确做法是读取请求体:

string bodyContent; using (var reader = new StreamReader(Request.Body, Encoding.UTF8)) { bodyContent = reader.ReadToEnd(); } // 然后用JsonConvert.DeserializeObject解析,或直接用JObject.Parse var jsonObj = Newtonsoft.Json.Linq.JObject.Parse(bodyContent); string deviceCode = jsonObj["deviceCode"]?.ToString();

这里有个容易忽略的问题:Request.Body只能读取一次。如果你在过滤器或中间件里先行读取了Body,后面再在控制器里用ReadToEnd()就会拿到空字符串。解决方法是读取时定位到流的起始位置:

Request.Body.Position = 0;

或者使用EnableBuffering()方法提前启用请求体缓冲。这个坑我印象特别深,因为光排查"为什么Body读出来是空的"就花了大半天时间。

4. 常见问题与排查技巧实录

4.1 ajax请求设置编码格式:中文乱码的根源

涉及中文场景的AJAX请求,最大的坑就是编码格式不统一。我见过无数开发者在遇到返回中文乱码时,第一反应是去改前台页面的charset,但问题往往出在服务端。排查乱码问题的顺序应该是这样的:

先看请求头里的Content-Type是否包含charset=utf-8。如果用的是jQuery,默认处理POST请求时会设置application/x-www-form-urlencoded; charset=UTF-8,这个一般没问题。但如果用了JSON.stringify并且自己指定了contentType,就一定要补上charset=utf-8这后半句。只写application/json的话,部分服务器默认按ISO-8859-1来处理响应体,中文必乱。

再看服务端页面的Response.ContentEncoding。ASP.NET里可以在Page_Load中显式设置:

Response.ContentEncoding = Encoding.UTF8; Request.ContentEncoding = Encoding.UTF8;

最后检查数据库连接字符串。如果连接MySQL时不加CharSet=utf8,即使前后端编码都对,数据从数据库里拿出来时就已经变成乱码了,那前端的排查就全部白费。这三个层级逐个确认下来,99%的乱码问题都能解决。

4.2 浏览器报invalid url的排查思路

热词里有一条是jq ajax syntaxerror: failed to execute 'open' on 'xmlhttprequest': invalid url,这个报错我印象非常深刻。它的含义是,XMLHttpRequest对象的open()方法接收到的URL格式不合法。

出现这个错误最常见的原因有两类。第一类,URL字符串里包含了非法字符。比如项目中用了模板字符串,某个变量的值是undefined或者null,拼接出来就成了/api/device/undefined。在这个路径下,如果服务端路由处理不了或者前端拦截器对这个路径做了特殊处理,浏览器就会报invalid url。

这类问题的排查思路很简单,在发起AJAX请求之前先打印一下URL:

console.log(requestUrl);

如果打印出来确实是undefined,那就往回找变量的赋值逻辑,多半是异步回调里数据还没返回就执行了拼接操作。

第二类原因是URL带了非法格式的query参数,比如某个参数值里面有空格或中文,却没有做encodeURIComponent编码。虽然浏览器一般会自动处理中文,但某些边缘字符比如#%&混在一起就会导致URL解析异常。我的习惯是,凡是动态拼接的参数,一律先编码再拼URL:

var fullUrl = "/api/device/list?keyword=" + encodeURIComponent(keyword) + "&page=" + pageIndex;

4.3 给ajax请求参数赋值时容易踩的坑

还有一个高频问题是怎么给AJAX请求的参数正确赋值。很多人在使用$.ajax的时候,对于data参数到底应该传对象还是序列化后的字符串拿不太准。这里我想说清楚一个底层逻辑。

jQuery的$.ajax在默认情况下,如果data传的是对象,processData会把它自动转换成key1=value1&key2=value2这种urlencoded格式。但如果contentType设置成了application/json,那processData的默认行为会和Content-Type冲突,数据格式对不上,服务端就解析不出来。

所以我的建议是遵循一个组合原则:

  • 传普通键值对,用application/x-www-form-urlencoded,data传对象即可。
  • 传嵌套结构或数组,用application/json,data需要JSON.stringify(obj)序列化。

还有一种情况也要注意:如果后端接口要求的参数名是data,你自己又把这个对象赋值给了data,服务端序列化时很容易出现"属性名冲突"的混淆。这种情况命名时要格外小心,前后端约定好字段名,避免歧义。

关于参数赋值,我还想提一个服务端的配套写法。ASP.NET的WebMethod静态方法接收JSON参数时,参数名一定要和前端传递的key严格一致,大小写也不能错。很多前端传的字段是驼峰命名,而后端用的是帕斯卡命名或者全小写,序列化时就会绑定失败。我见过最快的解决办法是直接用JObject.Parse或者JsonConvert.DeserializeObject<Dictionary<string, object>>来接收,这样就绕开了参数名匹配的限制,灵活处理各种字段名。

5. 实战手记:把GridView和AJAX组合成一套完整方案

5.1 一个设备台账页面的完整实现流程

说了这么多理论层面的东西,最后我来完整复盘一下当时给那家企业做的设备台账页面。这个页面综合了GridView、UpdatePanel、jQuery AJAX三种技术,能够很好地说明它们在真实项目中是如何分工协作的。

页面逻辑是这样的:顶部是搜索区和部门筛选下拉框,中间是GridView设备列表,支持分页、排序、状态高亮,最右侧有一个"同步状态"按钮,点击后通过AJAX调用后端接口,动态更新设备运行状态。

GridView部分仍然放在UpdatePanel里,负责处理分页、排序这些服务端事件。搜索和筛选通过AsyncPostBackTrigger触发UpdatePanel的回发。这样用户切换部门、翻页、排序时,体验都是无刷新的。

而"同步状态"这个功能,则是一次独立的jQuery AJAX请求,请求后端一个专门处理状态同步的接口。接口返回最新的设备状态数据之后,前端用$.each遍历JSON,在DOM中动态更新对应行的状态标签。

这里有一个很重要的设计思路:**粗粒度的交互操作交给UpdatePanel,细粒度的数据交互交给jQuery AJAX。**两者各司其职,而不是试图用一种技术解决所有问题。这是我在多个项目中总结出来的经验——试图用UpdatePanel做精细化的DOM操作很别扭,用纯AJAX做表格分页排序又太浪费人力,组合拳才是最优雅的方案。

5.2 分页性能优化与ViewState管理的经验

最后想分享一个关于性能的细节。GridView使用时会默认启用ViewState,这会导致页面上有一个很大的隐藏字段,存储了表格状态。如果数据量大、列数多,这个隐藏字段的大小可能达到几十KB甚至上百KB,严重影响页面加载速度。

优化的思路是:对于不需要在回发后保持状态的列,可以关闭ViewState;对于整个GridView,如果不需要在服务端事件中获取原始数据,可以设置EnableViewState="false"。但要注意,关闭ViewState之后,RowCommand事件中通过e.CommandArgument拿主键的方式仍然有效,因为数据是存在DataKeyNames里的。不过如果涉及编辑操作需要把整个行的数据都回传,那就不能轻易关掉ViewState,需要权衡取舍。

在实际项目中,我的做法是:只读展示的GridView直接关闭ViewState,配合DataKeyNames存储主键,这样既保障了事件回调的数据支撑,又显著减小了页面体积。如果必须支持行内编辑,就把编辑操作改成弹窗形式,通过AJAX传一整行的主键和修改字段,而不是依赖GridView的默认编辑模式。这样既保留了良好的交互体验,又绕开了ViewState的性能问题。

5.3 一些实用的前端配合技巧

既然说到了这里,再补充几个GridView和华前端配合上手就能用的小技巧。

一个是状态高亮。我们经常需要在设备状态异常时高亮显示该行,在RowDataBound事件里判断状态值,动态添加CSS类即可。这个写法非常直接:

protected void gvDevices_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { string status = DataBinder.Eval(e.Row.DataItem, "Status").ToString(); if (status == "2") // 异常状态 { e.Row.CssClass = "row-danger"; } } }

另一个是列宽与省略号的适配。GridView在窄屏下撑破布局是常见问题。CSS里给表格设置table-layout: fixed,给需要截断的列设置text-overflow: ellipsis; overflow: hidden; white-space: nowrap;,再配合标题提示,整体效果就很规整了。

还有遇到过一个很实用的小技巧。GridView导出Excel时,直接设置Response.ContentType = "application/vnd.ms-excel",再把GridView渲染到HtmlTextWriter里输出即可。这个方法不需要引入第三方组件,代码量也很少,和前端AJAX交互也能天然兼容,因为整个导出过程是服务端完成的,不涉及页面回发。

在做这几个功能时,我最深的体会是:技术本身没有什么新旧之分,关键是看它解决什么样的业务场景。GridView这套组合方案虽然"老",但在企业级信息化系统里依旧非常能打。它让我省下了大量处理表格交互细节的时间,把精力放在了业务流程和用户体验上。这也是为什么我每次做WebForms项目时,总是第一时间把这套组合方案排上日程。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 6:03:16

含风电并网和集群电动汽车的微电网调度Matlab实现

先说结论&#xff1a;把风电并网和集群电动汽车需求侧响应放进同一个微电网调度模型里&#xff0c;Matlab代码的复杂度会比你预想的高一个量级&#xff0c;但一旦把这条链路跑通&#xff0c;它对调度成本和风电消纳率的改善是实打实的。我最近在Matlab环境里完整搭建了这个优化…

作者头像 李华
网站建设 2026/9/8 6:02:58

AI边缘计算盒子选型指南:从算力指标到部署实战避坑

做AI落地项目这些年&#xff0c;被问最多的一个问题就是&#xff1a;AI边缘计算盒子到底选哪家&#xff1f;不是大家不愿意花钱&#xff0c;而是这个品类看起来长得都差不多——一个巴掌大的铁盒子&#xff0c;几个网口&#xff0c;写着支持多少TOPS算力&#xff0c;价格从几百…

作者头像 李华
网站建设 2026/9/8 6:02:18

从QEMU仿真源码到硬件复刻:静态评测证据工程实践

拿到 microduck-replica 这份开源项目时&#xff0c;我一开始以为又是一份“照抄板卡”的合集——把官方 demo 板的原理图搬过来&#xff0c;换几颗料&#xff0c;发一版 gerber 就完事。但把 README 和仓库结构完整过了一遍之后&#xff0c;我发现自己低估了它&#xff1a;这个…

作者头像 李华
网站建设 2026/9/8 6:02:14

Java开发者如何高效阅读源码并提升自己

在Java开发生态极度繁荣的今天&#xff0c;“熟练使用”已不再是核心竞争力。熟练工能调通API&#xff0c;但高手能在系统因高并发而崩盘时&#xff0c;通过深入理解框架原理迅速定位并解决问题。从“会用工具”到“理解工具”&#xff0c;再到“创造工具”&#xff0c;源码阅读…

作者头像 李华
网站建设 2026/9/8 6:02:11

PMSM伺服驱动器带宽设计全解析:从电流环到位置环的完整链路

上个月调试一台定制伺服驱动器&#xff0c;客户开口就要速度环带宽100Hz。我翻了设计图纸&#xff0c;电流环目标带宽给到3kHz&#xff0c;开关频率却只有8kHz&#xff0c;编码器用的是2500线增量式&#xff0c;机械侧还挂了个弹性联轴器。这个配置从纸面上就已经埋了雷&#x…

作者头像 李华
网站建设 2026/9/8 6:00:29

机械革命极光X游戏本值不值得买?2026各版本配置选购避坑指南

想买游戏本&#xff0c;预算卡在5000到7000这个区间&#xff0c;机械革命极光X几乎是绕不开的一个名字。社交平台上一搜&#xff0c;全是“XX价格入手极光X香不香”“极光X下车成功”之类的帖子&#xff0c;也有不少人在纠结要不要上车。这台机器确实把价格打得很低&#xff0c…

作者头像 李华