ASP.NET 內建 GridView 分頁功能雖方便,但 UI 風格固定、難以客製化。建立可重複使用的分頁使用者控制項,可統一專案分頁風格、集中邏輯維護。本文完整示範 Pagination.ascx 控制項的標記、後端程式碼、CSS 樣式與使用方式。
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Pagination.ascx.cs" Inherits="IOCS.WEB.UserControl.Pagination" %>
<link href="../Content/Css/Pager.css" rel="stylesheet" type="text/css" />
<div id="tbPage" class="pager" runat="server">
記錄總數:<asp:Label ID="LRecords" runat="server"></asp:Label>
總頁數:<asp:Label ID="LPages" runat="server"></asp:Label>
當前頁:<asp:Label ID="LPage" runat="server"></asp:Label>
<asp:LinkButton ID="LinkFirst" runat="server" CommandArgument="first" OnClick="PagerButtonClick" Text="首頁" />
<asp:LinkButton ID="LinkPrevious" runat="server" CommandArgument="prev" OnClick="PagerButtonClick" Text="上一頁" />
<asp:LinkButton ID="LinkNext" runat="server" CommandArgument="next" OnClick="PagerButtonClick" Text="下一頁" />
<asp:LinkButton ID="LinkLast" runat="server" CommandArgument="last" OnClick="PagerButtonClick" Text="末頁" />
轉到第<asp:TextBox ID="txtpage" CssClass="piut" runat="server" MaxLength="5" AutoPostBack="True" OnTextChanged="txtpage_TextChanged" />頁
</div>
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace IOCS.WEB.UserControl
{
public partial class Pagination : UserControl
{
// 對外事件:頁碼變更時通知父頁面重新綁定資料
public event EventHandler PageButtonClick;
// 目標 GridView
private GridView _gv;
public GridView TargetControlID
{
set { _gv = value; }
get { return _gv; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) { /* 首次載入可預設狀態 */ }
// 限制 txtpage 僅能輸入數字
txtpage.Attributes["onkeypress"] =
"return (event.charCode >= 48 && event.charCode <= 57) || event.charCode == 8;";
}
// 統一處理首頁、上一頁、下一頁、末頁
protected void PagerButtonClick(object sender, EventArgs e)
{
string arg = ((LinkButton)sender).CommandArgument;
switch (arg)
{
case "next":
if (_gv.PageIndex < _gv.PageCount - 1) _gv.PageIndex++;
break;
case "prev":
if (_gv.PageIndex > 0) _gv.PageIndex--;
break;
case "first":
_gv.PageIndex = 0;
break;
case "last":
if (_gv.PageCount > 0) _gv.PageIndex = _gv.PageCount - 1;
break;
default:
_gv.PageIndex = Convert.ToInt32(arg);
break;
}
PageButtonClick?.Invoke(sender, e); // 通知父頁面
}
// 依當前頁碼啟用/停用按鈕並切換樣式
public void SetPageButton()
{
bool isFirst = _gv.PageIndex == 0;
bool isLast = _gv.PageIndex == _gv.PageCount - 1;
bool hasMulti = _gv.PageCount > 1;
LinkFirst.Enabled = LinkPrevious.Enabled = !isFirst;
LinkNext.Enabled = LinkLast.Enabled = !isLast;
SetButtonStyle(LinkFirst, !isFirst);
SetButtonStyle(LinkPrevious, !isFirst);
SetButtonStyle(LinkNext, !isLast);
SetButtonStyle(LinkLast, !isLast);
txtpage.Enabled = hasMulti;
txtpage.Style["readonly"] = hasMulti ? "false" : "true";
}
private void SetButtonStyle(LinkButton btn, bool enabled)
{
btn.Style["color"] = enabled ? "#000" : "gray";
}
// 父頁面呼叫:設定總筆數並重新計算顯示資訊
public void SetPageRecord(int totalCount)
{
LRecords.Text = totalCount.ToString();
int mod = totalCount % _gv.PageSize;
LPages.Text = (mod == 0 ? totalCount / _gv.PageSize : totalCount / _gv.PageSize + 1).ToString();
LPage.Text = (_gv.PageIndex + 1).ToString();
tbPage.Visible = true;
SetPageButton();
}
// 手動輸入頁碼跳轉
protected void txtpage_TextChanged(object sender, EventArgs e)
{
if (int.TryParse(txtpage.Text.Trim(), out int idx) && idx >= 1 && idx <= _gv.PageCount)
{
_gv.PageIndex = idx - 1;
PageButtonClick?.Invoke(sender, e);
}
else
{
ScriptManager.RegisterStartupScript(this, GetType(), "alert", "alert('頁碼超出範圍或格式錯誤');", true);
}
}
}
}
<%@ Register Src="~/UserControl/Pagination.ascx" TagPrefix="uc" TagName="Pagination" %>
<asp:GridView ID="GridView1" runat="server" AllowPaging="True" PageSize="10" OnPageIndexChanging="GridView1_PageIndexChanging"></asp:GridView>
<uc:Pagination ID="Pager1" runat="server" />
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Pager1.TargetControlID = GridView1;
Pager1.PageButtonClick += Pager1_PageButtonClick;
BindData();
}
}
private void BindData()
{
// 取得資料總筆數
int total = GetTotalCount();
GridView1.DataSource = GetPageData(GridView1.PageIndex, GridView1.PageSize);
GridView1.DataBind();
// 更新分頁控制項顯示
Pager1.SetPageRecord(total);
}
protected void Pager1_PageButtonClick(object sender, EventArgs e)
{
BindData(); // 重新綁定資料
}
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
BindData();
}
.pager { padding: 10px; text-align: center; font-family: Microsoft JhengHei; }
.pager a { margin: 0 5px; text-decoration: none; color: #000; }
.pager a:hover { text-decoration: underline; }
.pager .piut { width: 40px; text-align: center; }
PageButtonClick 事件處理,符合單一職責原則。TargetControlID 屬性指定任意 GridView,一個控制項可服務多個頁面。SetPageRecord 由父頁面在每次 DataBind 後呼叫,確保顯示資訊與實際資料一致。onkeypress + 後端 TryParse 雙重防護,避免非數字導致例外。SetPageButton 中動態產生 1~10 頁的 LinkButton,取代純文字輸入。.pagination、.page-link 等標準類別,直接套用框架樣式。自訂分頁使用者控制項將分頁邏輯封裝、UI 樣式統一,大幅降低專案維護成本。本文提供的實作已涵蓋核心功能(首/末頁、上/下頁、跳頁、狀態同步),可直接套用或依專案需求擴充。