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控件,完全独立,你只需要在窗体的按钮事件中调用对应方法即可。

相关推荐
科技道人5 小时前
记录 默认置灰/禁用 app ‘Search Engine Selector‘ 的disable按钮
开发语言·前端·javascript
-SOLO-7 小时前
Android Event 日志完全指南
android
逝水无殇8 小时前
C# 异常处理详解
开发语言·后端·c#
壮哥_icon8 小时前
【Android 系统开发】从掉帧卡顿到丝滑:高频硬件中断(IRQ)的 CPU 亲和性性能优化实战
android·性能优化
千里马学框架8 小时前
Android Framework 新手学习踩坑建议指南
android·智能手机·性能优化·framework·aaos·车载开发·系统工程师
玖玥拾9 小时前
C# 语言进阶(十五)C# 游戏服务端 MySQL 数据库
服务器·开发语言·网络·数据库·mysql·c#
铅笔侠_小龙虾10 小时前
Rust 学习目录
开发语言·学习·rust
我命由我1234510 小时前
执行 Gradle 指令报错,无法将“grep”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
云泽80810 小时前
从零吃透 C++ 异常:抛出捕获、栈展开、异常重抛与编码规范详解
开发语言·c++·代码规范
灯澜忆梦10 小时前
GO---可见性规则
开发语言·golang