GridView 內建分頁功能只需設定幾個屬性並處理 PageIndexChanging 事件即可啟用。但實務上常遇到:自訂分頁 UI、大量資料效能、分頁狀態保持、AJAX 部分更新等需求。
AllowPaging="true"PageSize="10" (預設 10)PagerSettings-Mode="NumericFirstLast" (或 NextPrevious、Numeric)OnPageIndexChanging="GridView1_PageIndexChanging"protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
BindGridView(); // 重新綁定資料
}
<asp:GridView ID="GridView1" runat="server"
AllowPaging="true" PageSize="15"
AutoGenerateColumns="false"
OnPageIndexChanging="GridView1_PageIndexChanging"
OnSorting="GridView1_Sorting"
PagerSettings-Mode="NumericFirstLast"
PagerSettings-PageButtonCount="10"
PagerStyle-CssClass="grid-pager"
CssClass="table table-striped">
<Columns>
<asp:BoundField DataField="Id" HeaderText="編號" SortExpression="Id" />
<asp:BoundField DataField="Name" HeaderText="名稱" SortExpression="Name" />
<asp:BoundField DataField="CreateTime" HeaderText="建立時間" DataFormatString="{0:yyyy/MM/dd HH:mm}" />
</Columns>
</asp:GridView>
private void BindGridView()
{
// 範例:從資料庫撈資料
string sql = "SELECT Id, Name, CreateTime FROM Products WHERE IsActive=1";
using (var conn = new SqlConnection(ConnStr))
using (var da = new SqlDataAdapter(sql, conn))
{
var dt = new DataTable();
da.Fill(dt);
// 若有排序狀態,套用排序
if (ViewState["SortExpr"] != null)
{
dt.DefaultView.Sort = ViewState["SortExpr"] + " " + ViewState["SortDir"];
}
GridView1.DataSource = dt;
GridView1.DataBind();
}
}
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
BindGridView();
}
<PagerTemplate>
<asp:LinkButton runat="server" CommandName="Page" CommandArgument="First" Text="<< 首頁" />
<asp:LinkButton runat="server" CommandName="Page" CommandArgument="Prev" Text="< 上頁" />
<span class="page-info">第 <%# Container.PageIndex + 1 %> 頁 / 共 <%# Container.PageCount %> 頁</span>
<asp:LinkButton runat="server" CommandName="Page" CommandArgument="Next" Text="下頁 >" />
<asp:LinkButton runat="server" CommandName="Page" CommandArgument="Last" Text="尾頁 >>" />
<asp:TextBox ID="txtGoPage" runat="server" Width="40" CssClass="page-input" />
<asp:LinkButton runat="server" CommandName="Page" CommandArgument='<%# ((TextBox)Container.FindControl("txtGoPage")).Text %>' Text="跳轉" />
</PagerTemplate>
搭配 CSS 美化,打造類似現代前端分頁元件的體驗。
預設 DataTable 全撈再分頁,資料量大時記憶體與速度皆不可接受。改用 SQL Server OFFSET/FETCH (2012+) 或 ROW_NUMBER() (2005+)。
private DataTable GetPagedData(int pageIndex, int pageSize, out int totalCount)
{
string sql = @"
SELECT COUNT(*) FROM Products WHERE IsActive=1;
SELECT Id, Name, CreateTime
FROM Products
WHERE IsActive=1
ORDER BY CreateTime DESC
OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY;";
using (var conn = new SqlConnection(ConnStr))
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@Offset", pageIndex * pageSize);
cmd.Parameters.AddWithValue("@PageSize", pageSize);
conn.Open();
using (var reader = cmd.ExecuteReader())
{
totalCount = reader.Read() ? reader.GetInt32(0) : 0;
reader.NextResult();
var dt = new DataTable();
dt.Load(reader);
return dt;
}
}
}
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
int total;
GridView1.DataSource = GetPagedData(e.NewPageIndex, GridView1.PageSize, out total);
GridView1.VirtualItemCount = total; // 啟用自訂分頁計數
GridView1.PageIndex = e.NewPageIndex;
GridView1.DataBind();
}
需設定 GridView.AllowCustomPaging="true" 並指定 VirtualItemCount。
<asp:UpdatePanel ID="upGrid" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:GridView ... />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="GridView1" EventName="PageIndexChanging" />
</Triggers>
</asp:UpdatePanel>
避免整頁重新整理,提升使用者體驗。
// 儲存於 Session,Key 含頁面識別
string pageKey = "GridView1_PageIndex_" + Request.Path;
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
Session[pageKey] = e.NewPageIndex;
BindGridView();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack && Session[pageKey] != null)
{
GridView1.PageIndex = (int)Session[pageKey];
}
}
| 問題 | 原因 | 解決 |
|---|---|---|
| 分頁按鈕不顯示 | 資料筆數 ≤ PageSize | 正常行為;或設 PagerSettings-Visible="true" 強制顯示 |
| 點擊分頁無反應 | 缺少 OnPageIndexChanging 或未重新綁定 | 檢查事件綁定與 BindGridView() |
| 分頁後排序消失 | 重新綁定未套用排序 ViewState | BindGridView() 中套用 dt.DefaultView.Sort |
| 自訂分頁總筆數錯誤 | 未設定 VirtualItemCount | 查詢 COUNT(*) 並指派 |
GridView 分頁核心三步驟:開啟屬性 → 處理 PageIndexChanging → 重新綁定。實務上務必搭配**資料庫端分頁**、**排序狀態保持**、**非同步更新**三大增強,才能應對真實業務場景。