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

相关推荐
在繁华处19 小时前
Java从零到熟练(四):面向对象基础
java·开发语言
Unbelievabletobe19 小时前
解决了股票api接口盘后数据更新慢的问题
大数据·开发语言·python
程序员陆业聪20 小时前
绕过Frida/Xposed的最后防线:SVC直接系统调用与Native反Hook实战
android
程序员陆业聪20 小时前
WebView与原生JS交互:JSBridge生产级实现与安全防护
android
不会C语言的男孩20 小时前
C++ Primer 第2章:变量和基本类型
开发语言·c++
在繁华处21 小时前
Java从零到熟练(三):流程控制
java·开发语言·python
云泽80821 小时前
C++ 可调用对象通关指南:深度解析 Lambda 表达式、function 包装器与 bind 绑定器
开发语言·c++·算法
我命由我123451 天前
Android 开发问题:MlKitException: An internal error occurred during initialization.
android·java·java-ee·android jetpack·android-studio·androidx·android runtime
星恒随风1 天前
Python 基础语法详解(一):从表达式、变量到数据类型
开发语言·笔记·python·学习
888CC++1 天前
java 并发编程
java·开发语言·python