WebForms中GridView分页仅查询单页数据的实现方法
没问题,这个需求在WebForms里完全可以实现,核心就是放弃GridView的默认分页机制,改用自定义分页——也就是每次只从数据库拉取当前页需要的10条数据,而不是全表查询。我给你一步步拆解怎么做:
默认的GridView分页是先把全表数据查出来放到内存里,再截取当前页的内容,这在数据量大的时候肯定会卡。自定义分页则是让数据库只返回当前页的10条数据,同时获取总记录数来生成分页导航。
1. 准备数据访问方法
你需要写两个数据库操作方法:一个用来获取指定页的数据,另一个用来获取总记录数。这里以SQL Server为例(如果是MySQL/Oracle,语法略有不同,后面会提):
获取分页数据的方法
public DataTable GetPagedData(int pageIndex, int pageSize) { // 计算当前页的起始行和结束行(SQL Server的ROW_NUMBER是从1开始的) int startRow = (pageIndex - 1) * pageSize + 1; int endRow = pageIndex * pageSize; string sql = @" SELECT * FROM ( -- 先给每条数据加行号,注意这里的ORDER BY要换成你实际的排序字段 SELECT *, ROW_NUMBER() OVER(ORDER BY YourSortColumn DESC) AS RowNum FROM YourTableName ) AS TempTable WHERE RowNum BETWEEN @StartRow AND @EndRow"; DataTable result = new DataTable(); // 用using自动释放连接,避免资源泄漏 using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["YourConnString"].ConnectionString)) { using (SqlCommand cmd = new SqlCommand(sql, conn)) { // 参数化查询,防止SQL注入 cmd.Parameters.AddWithValue("@StartRow", startRow); cmd.Parameters.AddWithValue("@EndRow", endRow); SqlDataAdapter adapter = new SqlDataAdapter(cmd); adapter.Fill(result); } } return result; }
获取总记录数的方法
public int GetTotalRecordCount() { string sql = "SELECT COUNT(*) FROM YourTableName"; using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["YourConnString"].ConnectionString)) { using (SqlCommand cmd = new SqlCommand(sql, conn)) { conn.Open(); return (int)cmd.ExecuteScalar(); } } }
注意:如果是MySQL,分页用
LIMIT (pageIndex-1)*pageSize, pageSize;如果是Oracle,用ROWNUM来筛选,语法会稍有不同,核心都是让数据库做分页筛选。
2. 配置页面控件
GridView设置
把GridView的AllowPaging设为false(因为我们不用它的默认分页),然后定义好你的列:
<asp:GridView ID="gvData" runat="server" AutoGenerateColumns="false" Width="100%"> <Columns> <asp:BoundField DataField="Id" HeaderText="ID" /> <asp:BoundField DataField="Name" HeaderText="名称" /> <!-- 其他列根据你的需求添加 --> </Columns> </asp:GridView>
分页导航控件
推荐用第三方的AspNetPager控件(这个是WebForms里常用的分页控件,NuGet可以直接安装),配置起来很方便:
<webdiyer:AspNetPager ID="anpPager" runat="server" PageSize="10" OnPageChanged="anpPager_PageChanged" AlwaysShow="true" ShowPageIndexBox="true" LayoutType="Table"> </webdiyer:AspNetPager>
如果不想用第三方控件,也可以自己写上一页/下一页按钮,维护当前页码的ViewState就行,后面会提。
3. 页面后台逻辑
首次加载绑定数据
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // 先获取总记录数,传给分页控件 anpPager.RecordCount = GetTotalRecordCount(); // 绑定第一页数据 BindGridData(anpPager.CurrentPageIndex); } } // 封装绑定数据的方法 private void BindGridData(int pageIndex) { gvData.DataSource = GetPagedData(pageIndex, anpPager.PageSize); gvData.DataBind(); }
分页变更事件
当用户点击分页按钮时,重新绑定对应页的数据:
protected void anpPager_PageChanged(object sender, EventArgs e) { BindGridData(anpPager.CurrentPageIndex); }
4. 自定义分页按钮(不用第三方控件的方案)
如果不想依赖第三方控件,自己做分页按钮也可以:
- 先在页面加几个控件:
<asp:Button ID="btnPrev" runat="server" Text="上一页" OnClick="btnPrev_Click" /> <asp:Label ID="lblPageInfo" runat="server" Text="第1页/共0页"></asp:Label> <asp:Button ID="btnNext" runat="server" Text="下一页" OnClick="btnNext_Click" />
- 后台维护当前页码的ViewState:
// 用ViewState保存当前页码,避免回发丢失 private int CurrentPage { get { return ViewState["CurrentPage"] == null ? 1 : (int)ViewState["CurrentPage"]; } set { ViewState["CurrentPage"] = value; } }
- 按钮点击事件:
protected void btnPrev_Click(object sender, EventArgs e) { int totalPages = (int)Math.Ceiling(GetTotalRecordCount() / (double)10); if (CurrentPage > 1) { CurrentPage--; BindGridData(CurrentPage); UpdatePageInfoLabel(totalPages); } } protected void btnNext_Click(object sender, EventArgs e) { int totalPages = (int)Math.Ceiling(GetTotalRecordCount() / (double)10); if (CurrentPage < totalPages) { CurrentPage++; BindGridData(CurrentPage); UpdatePageInfoLabel(totalPages); } } // 更新页码信息标签 private void UpdatePageInfoLabel(int totalPages) { lblPageInfo.Text = $"第{CurrentPage}页/共{totalPages}页"; }
然后在首次加载时也要更新页码标签:
if (!IsPostBack) { int totalPages = (int)Math.Ceiling(GetTotalRecordCount() / (double)10); UpdatePageInfoLabel(totalPages); BindGridData(1); }
- 排序处理:如果需要支持GridView排序,要把
ROW_NUMBER()里的ORDER BY换成动态的排序字段,比如根据用户点击的列来修改SQL里的排序条件。 - 参数化查询:一定要用参数化查询,不要直接拼接SQL字符串,防止SQL注入。
- 数据库连接:用
using语句自动释放数据库连接,避免资源泄漏。
这样每次页面加载或者点击分页按钮时,只会从数据库查询当前页的10条数据,大大减少了数据传输量,页面加载速度会快很多。
内容的提问来源于stack exchange,提问作者Konstantin Kožuchov

