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. 获取数据 :使用 StartIndexPageSize 查询数据库
  6. 更新UI :根据 HasPrevPage/HasNextPage 控制按钮启用状态

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

相关推荐
布莱克6057 小时前
C++拷贝构造与拷贝赋值运算符的区别详解
开发语言·c++
lhldsg7 小时前
全民健身解决方案:从共享球场到智能运营的技术实践
java·大数据·开发语言·需求分析
字节暗面7 小时前
四款 APP 加固强度测评:让 AI 拆了四个包,结果有点出乎意料
android·逆向工程·加固
网安蟹佬霸7 小时前
蓝队防御实战:SIEM与SOAR构建安全运营中心(万字详解+实战配置)
android·安全·web安全·网络安全·网安
归去来?8 小时前
Python 常用优雅写法
开发语言·python
devilnumber8 小时前
Java 30 组高频技术 / 知识点多角度对比
java·开发语言
何以解忧,唯有..8 小时前
Python 异常处理完全指南:从基础到高级实践
开发语言·前端·python
gugucoding8 小时前
57. 【Java】日志框架:SLF4J与Logback
java·开发语言·logback
此生决int8 小时前
深入理解C++系列(15)——AVL树
开发语言·c++
筱璦8 小时前
PHP+ VUE3机构级股票分仓管理交易系统源码可出
开发语言·php·vue3·量化·股票分仓