首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET 自訂分頁使用者控制項 完整實作教學

     編輯:ASP.NET 基礎

前言

ASP.NET 內建 GridView 分頁功能雖方便,但 UI 風格固定、難以客製化。建立可重複使用的分頁使用者控制項,可統一專案分頁風格、集中邏輯維護。本文完整示範 Pagination.ascx 控制項的標記、後端程式碼、CSS 樣式與使用方式。

1. 控制項標記

<%@ 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>

2. 後端核心邏輯

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);
            }
        }
    }
}

3. 父頁面使用方式

<%@ 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();
}

4. CSS 樣式範例

.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; }

關鍵設計亮點

  • 事件解耦:控制項只負責計算頁碼、切換 UI 狀態,實際資料查詢交由父頁面 PageButtonClick 事件處理,符合單一職責原則。
  • 泛用性:透過 TargetControlID 屬性指定任意 GridView,一個控制項可服務多個頁面。
  • 狀態同步:SetPageRecord 由父頁面在每次 DataBind 後呼叫,確保顯示資訊與實際資料一致。
  • 輸入驗證:前端 onkeypress + 後端 TryParse 雙重防護,避免非數字導致例外。

擴充建議

  1. 數字頁碼連結:在 SetPageButton 中動態產生 1~10 頁的 LinkButton,取代純文字輸入。
  2. AJAX 分頁:配合 UpdatePanel 或前端 fetch,實現無重整分頁。
  3. 頁面大小切換:加入 DropDownList 讓使用者自訂 PageSize,觸發事件通知父頁面。
  4. Bootstrap 整合:將 CSS 改為 .pagination、.page-link 等標準類別,直接套用框架樣式。

總結

自訂分頁使用者控制項將分頁邏輯封裝、UI 樣式統一,大幅降低專案維護成本。本文提供的實作已涵蓋核心功能(首/末頁、上/下頁、跳頁、狀態同步),可直接套用或依專案需求擴充。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved