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

打造通用 ASP.NET 資料分頁控件:支援 Repeater/GridView、資料敏感、外觀可配置的完整方案

     編輯:關於ASP.NET

為什麼需要通用分頁控件?

  • DataGrid 內建分頁功能受限:位置固定、樣式難調整、不支援垂直佈局。
  • Repeater 靈活但無分頁,需自行實作。
  • 專案中資料來源、顯示控件多變,針對每種情況寫分頁極度浪費。

優秀通用分頁控件應具備的 8 大特性

  1. 首頁、上一頁、下一頁、末頁導航按鈕。
  2. 資料敏感:總筆數 ≤ 頁面大小時隱藏;首頁隱藏首頁/上一頁;末頁隱藏下一頁/末頁。
  3. 不依賴特定顯示控件:可搭配 Repeater、GridView、ListView、自訂控件。
  4. 適應多種資料來源**:DataTable、List、IQueryable、自訂分頁介面。
  5. 外觀易配置、易整合**:樣式類別、模板、CSS 隔離。
  6. 分頁就緒事件通知**:其他控件可訂閱重新繫結。
  7. 低門檻**:拖曳即用,屬性視窗設定。
  8. 提供分頁資訊屬性**:CurrentPageIndex、PageSize、TotalRecords、TotalPages 等。

核心介面設計

public interface IPagerDataSource
{
    int TotalRecords { get; }
    IEnumerable GetPageData(int pageIndex, int pageSize);
}

public class PagerControl : WebControl, INamingContainer
{
    // 核心屬性
    public int PageSize { get; set; } = 10;
    public int CurrentPageIndex { get; private set; } = 0;
    public int TotalRecords { get; private set; }
    public int TotalPages => (int)Math.Ceiling((double)TotalRecords / PageSize);

    // 外觀屬性
    public string CssClass { get; set; } = "pager";
    public string FirstPageText { get; set; } = "首頁";
    public string PrevPageText { get; set; } = "上一頁";
    public string NextPageText { get; set; } = "下一頁";
    public string LastPageText { get; set; } = "末頁";
    public bool ShowPageNumbers { get; set; } = true;
    public int PageNumberCount { get; set; } = 10;

    // 事件
    public event EventHandler PageChanged;

    // 資料來源設定
    public IPagerDataSource DataSource { get; set; }

    // 生命週期
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        if (DataSource != null)
        {
            TotalRecords = DataSource.TotalRecords;
            // 處理頁碼傳遞 (QueryString/PostBack)
            string pageArg = Page.Request.QueryString["page"] ?? Page.Request.Form["pager_page"];
            if (int.TryParse(pageArg, out int idx) && idx >= 0 && idx < TotalPages)
                CurrentPageIndex = idx;
        }
        EnsureChildControls();
    }

    protected override void CreateChildControls()
    {
        Controls.Clear();
        if (TotalPages <= 1) return; // 資料敏感:單頁隱藏

        var ul = new HtmlGenericControl("ul") { Attributes = { ["class"] = CssClass } };
        Controls.Add(ul);

        // 首頁/上一頁
        AddButton(ul, "first", FirstPageText, 0, CurrentPageIndex == 0);
        AddButton(ul, "prev", PrevPageText, CurrentPageIndex - 1, CurrentPageIndex == 0);

        // 頁碼
        if (ShowPageNumbers)
        {
            int start = Math.Max(0, CurrentPageIndex - PageNumberCount / 2);
            int end = Math.Min(TotalPages - 1, start + PageNumberCount - 1);
            start = Math.Max(0, end - PageNumberCount + 1);
            for (int i = start; i <= end; i++)
                AddButton(ul, "num", (i + 1).ToString(), i, false, i == CurrentPageIndex);
        }

        // 下一頁/末頁
        AddButton(ul, "next", NextPageText, CurrentPageIndex + 1, CurrentPageIndex == TotalPages - 1);
        AddButton(ul, "last", LastPageText, TotalPages - 1, CurrentPageIndex == TotalPages - 1);
    }

    private void AddButton(Control container, string type, string text, int pageIndex, bool disabled, bool active = false)
    {
        var li = new HtmlGenericControl("li");
        if (disabled) li.Attributes["class"] = "disabled";
        if (active) li.Attributes["class"] = (li.Attributes["class"] ?? "") + " active";

        var a = new HtmlAnchor { HRef = $"?page={pageIndex}", InnerText = text };
        if (disabled) a.Attributes["onclick"] = "return false;";
        li.Controls.Add(a);
        container.Controls.Add(li);
    }

    protected virtual void OnPageChanged(PageChangedEventArgs e)
    {
        PageChanged?.Invoke(this, e);
    }
}

public class PageChangedEventArgs : EventArgs
{
    public int NewPageIndex { get; set; }
    public int PageSize { get; set; }
}

搭配 Repeater 使用範例

<%@ Register TagPrefix="cc" Namespace="MyControls" Assembly="MyControls" %>
<cc:PagerControl ID="Pager1" runat="server" PageSize="10"
    FirstPageText="<<" PrevPageText="<" NextPageText=">" LastPageText=">>"
    OnPageChanged="Pager1_PageChanged" />

<asp:Repeater ID="rptData" runat="server">
  <ItemTemplate>
    <div><%# Eval("Title") %></div>
  </ItemTemplate>
</asp:Repeater>
public partial class DemoPage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            Pager1.DataSource = new ArticlePagerSource(); // 實作 IPagerDataSource
            Pager1.PageChanged += Pager1_PageChanged;
            BindData();
        }
    }

    private void BindData()
    {
        var data = ((IPagerDataSource)Pager1.DataSource).GetPageData(Pager1.CurrentPageIndex, Pager1.PageSize);
        rptData.DataSource = data;
        rptData.DataBind();
    }

    protected void Pager1_PageChanged(object sender, PageChangedEventArgs e)
    {
        BindData();
    }
}

資料來源實作範例

public class ArticlePagerSource : IPagerDataSource
{
    public int TotalRecords => DbHelper.ExecuteScalar("SELECT COUNT(*) FROM Articles WHERE IsPublished=1");

    public IEnumerable GetPageData(int pageIndex, int pageSize)
    {
        string sql = @"
            SELECT * FROM Articles 
            WHERE IsPublished=1 
            ORDER BY PublishDate DESC
            OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY";
        return DbHelper.Query
(sql, new { Offset = pageIndex * pageSize, PageSize = pageSize }); } }

樣式建議 (CSS)

.pager { display:flex; list-style:none; padding:0; gap:4px; justify-content:center; }
.pager li a { display:block; padding:6px 12px; border:1px solid #ddd; border-radius:3px; color:#333; text-decoration:none; }
.pager li.active a { background:#007bff; color:#fff; border-color:#007bff; }
.pager li.disabled a { color:#999; pointer-events:none; background:#f5f5f5; }

總結

通用分頁控件核心在於:介面抽象資料來源、`IPagerDataSource` 解耦分頁邏輯與資料存取;資料敏感渲染自動隱藏無意義按鈕;事件驅動通知顯示控件重新繫結。此架構可輕鬆擴充 AJAX 分頁、無限滾動、URL 友善路由等進階功能。

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