C# winform 自制分页功能

一个精简的分页类,配合现有的界面按钮使用:

分页类(Pagination.cs)

csharp 复制代码
using System;
using System.Collections.Generic;

/// <summary>
/// 分页管理类
/// </summary>
public class Pagination
{
    private int _pageIndex = 1;      // 当前页码
    private int _pageSize = 10;       // 每页显示条数
    private int _totalCount = 0;      // 总记录数
    private int _totalPages = 0;      // 总页数

    /// <summary>
    /// 页码改变事件(在UI中订阅此事件来刷新数据)
    /// </summary>
    public event Action OnPageChanged;

    /// <summary>
    /// 当前页码(从1开始)
    /// </summary>
    public int PageIndex
    {
        get { return _pageIndex; }
        set
        {
            if (value >= 1 && value <= _totalPages)
            {
                _pageIndex = value;
                OnPageChanged?.Invoke();
            }
        }
    }

    /// <summary>
    /// 每页显示条数
    /// </summary>
    public int PageSize
    {
        get { return _pageSize; }
        set
        {
            if (value > 0)
            {
                _pageSize = value;
                // 改变每页条数后重置到第一页
                _pageIndex = 1;
                // 重新计算总页数
                RecalculateTotalPages();
                OnPageChanged?.Invoke();
            }
        }
    }

    /// <summary>
    /// 总记录数
    /// </summary>
    public int TotalCount
    {
        get { return _totalCount; }
        set
        {
            _totalCount = value;
            RecalculateTotalPages();
        }
    }

    /// <summary>
    /// 总页数
    /// </summary>
    public int TotalPages => _totalPages;

    /// <summary>
    /// 是否有上一页
    /// </summary>
    public bool HasPrevPage => _pageIndex > 1;

    /// <summary>
    /// 是否有下一页
    /// </summary>
    public bool HasNextPage => _pageIndex < _totalPages;

    /// <summary>
    /// 数据起始索引(用于SQL查询的 OFFSET,从0开始)
    /// </summary>
    public int StartIndex => (_pageIndex - 1) * _pageSize;

    /// <summary>
    /// 重新计算总页数
    /// </summary>
    private void RecalculateTotalPages()
    {
        if (_totalCount == 0)
        {
            _totalPages = 1;
        }
        else
        {
            _totalPages = (int)Math.Ceiling((double)_totalCount / _pageSize);
        }

        // 如果当前页超出总页数,调整到最后一页
        if (_pageIndex > _totalPages)
        {
            _pageIndex = _totalPages;
        }
    }

    /// <summary>
    /// 上一页
    /// </summary>
    public void PrevPage()
    {
        if (HasPrevPage)
        {
            PageIndex--;
        }
    }

    /// <summary>
    /// 下一页
    /// </summary>
    public void NextPage()
    {
        if (HasNextPage)
        {
            PageIndex++;
        }
    }

    /// <summary>
    /// 跳转到指定页
    /// </summary>
    /// <param name="pageNumber">页码(从1开始)</param>
    /// <returns>是否跳转成功</returns>
    public bool GoToPage(int pageNumber)
    {
        if (pageNumber >= 1 && pageNumber <= _totalPages)
        {
            PageIndex = pageNumber;
            return true;
        }
        return false;
    }

    /// <summary>
    /// 获取分页信息文本(用于显示在界面上)
    /// </summary>
    public string GetPageInfoText()
    {
        return $"第 {_pageIndex} / {_totalPages} 页,共 {_totalCount} 条记录";
    }

    /// <summary>
    /// 获取按钮状态(用于界面按钮的Enabled属性)
    /// </summary>
    public (bool canPrev, bool canNext) GetButtonStatus()
    {
        return (HasPrevPage, HasNextPage);
    }
}

使用示例(在窗体中)

csharp 复制代码
public partial class MainForm : Form
{
    private Pagination _pagination;
    private DataTable _allData;  // 全部数据

    public MainForm()
    {
        InitializeComponent();
        InitPagination();
        LoadMockData();
        LoadPageData();
    }

    private void InitPagination()
    {
        _pagination = new Pagination();
        _pagination.PageSize = 10;  // 设置每页条数
        _pagination.OnPageChanged += () =>
        {
            // 页码改变时重新加载数据
            LoadPageData();
            UpdateUI();
        };
    }

    private void UpdateUI()
    {
        // 更新按钮状态
        var (canPrev, canNext) = _pagination.GetButtonStatus();
        btnPrev.Enabled = canPrev;
        btnNext.Enabled = canNext;

        // 更新显示信息
        lblPageInfo.Text = _pagination.GetPageInfoText();
    }

    // 按钮事件
    private void btnPrev_Click(object sender, EventArgs e)
    {
        _pagination.PrevPage();
    }

    private void btnNext_Click(object sender, EventArgs e)
    {
        _pagination.NextPage();
    }

    // 跳转按钮
    private void btnJump_Click(object sender, EventArgs e)
    {
        if (int.TryParse(txtJumpPage.Text, out int page))
        {
            if (!_pagination.GoToPage(page))
            {
                MessageBox.Show($"页码范围:1-{_pagination.TotalPages}");
            }
        }
        else
        {
            MessageBox.Show("请输入有效的页码");
        }
    }

    // 设置每页条数
    private void cmbPageSize_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (cmbPageSize.SelectedItem != null)
        {
            int pageSize = Convert.ToInt32(cmbPageSize.SelectedItem);
            _pagination.PageSize = pageSize;
        }
    }

    // 加载分页数据
    private void LoadPageData()
    {
        // 方法1:从内存数据中取
        var pageData = _allData.Rows
            .Cast<DataRow>()
            .Skip(_pagination.StartIndex)
            .Take(_pagination.PageSize)
            .CopyToDataTable();

        dataGridView1.DataSource = pageData;

        // 方法2:从数据库查询(推荐)
        // string sql = @"
        //     SELECT * FROM Users 
        //     ORDER BY ID 
        //     OFFSET @Offset ROWS 
        //     FETCH NEXT @PageSize ROWS ONLY";
        // 
        // var parameters = new 
        // { 
        //     Offset = _pagination.StartIndex, 
        //     PageSize = _pagination.PageSize 
        // };
        // dataGridView1.DataSource = ExecuteQuery(sql, parameters);
    }

    private void LoadMockData()
    {
        // 模拟155条数据
        _allData = new DataTable();
        _allData.Columns.Add("ID", typeof(int));
        _allData.Columns.Add("Name", typeof(string));

        for (int i = 1; i <= 155; i++)
        {
            _allData.Rows.Add(i, $"用户{i}");
        }

        // 设置总记录数
        _pagination.TotalCount = _allData.Rows.Count;
    }
}

核心属性说明

属性 说明
PageIndex 当前页码(从1开始)
PageSize 每页条数
TotalCount 总记录数(外部赋值)
TotalPages 总页数(自动计算)
HasPrevPage 是否有上一页
HasNextPage 是否有下一页
StartIndex 数据起始索引(从0开始,用于SQL的OFFSET)

使用步骤

  1. 实例化分页类 :_pagination = new Pagination();
  2. 订阅事件 :_pagination.OnPageChanged += LoadData;
  3. 设置总记录数 :_pagination.TotalCount = totalRows;
  4. 按钮事件调用 :_pagination.PrevPage() / NextPage() / GoToPage()
  5. 获取数据 :使用 StartIndex 和 PageSize 查询数据库
  6. 更新UI :根据 HasPrevPage/HasNextPage 控制按钮启用状态

这个分页类不包含任何UI控件,完全独立,你只需要在窗体的按钮事件中调用对应方法即可。

相关推荐
吴可可1237 分钟前
ActiveX调用WScript.Shell原理揭秘
开发语言
传奇开心果编程25 分钟前
【Flutter踩坑排雷】第28课:平台目录缺失与修复坑|`flutter create` 的“重建”与“覆盖”边界
android·flutter·ios·移动开发·跨平台·dart·声明式ui
晴天的雨.9921 小时前
【C++】继承篇
java·开发语言·c++
SomeOtherTime1 小时前
第 1 讲:内存布局与所有权解剖——栈帧、胖指针与“移动/拷贝”在汇编层面的真实面目
java·开发语言·汇编
总要学点什么2 小时前
第106篇:三维特效-流动线效果——让一颗光点沿整条线一路滚到头
开发语言·javascript·ecmascript·gis·webgl·材质·cesium
longxibo10 小时前
【AIBIZ低代码平台:能长出业务系统的平台】
android·低代码·rxjava
大可不必了12 小时前
03 函数定义和调用
开发语言·python
I_belong_to_jesus12 小时前
C++关于分支预测的优化1
开发语言·c++·算法
承渊政道13 小时前
【Python编程—从入门到实践】(记分与闯关:用Python+Pygame,打造越战越精彩的太空大战!)
开发语言·python·pycharm·游戏程序·pygame
爱学习的程序媛13 小时前
Python常用框架梳理
开发语言·后端·python·ai·web·后端框架·python框架