C# WinForms DataGridView 实现手动与自动翻页

陈默
陈默
发布时间:2026-10-13| 4人浏览过
原创

本文详细讲解了在C# WinForms开发中,如何让表格控件DataGridView实现类似幻灯片或监控大屏的分页效果。主要包含两种方案:一是通过隐藏原生滚动条并结合坐标属性实现平滑的手动翻页;二是利用Timer定时器与数据集切片技术,实现数据的定时自动轮播。文中附带了完整的计算逻辑代码及注意事项。

手动翻页:消除滚动条并控制视口

默认情况下,DataGridView拥有内置的滚动条。要实现自定义分页(如翻页按钮),首先需要禁用系统的自动滚动行为,并将视图精准定位到第一行或最后一行。

第1步:禁用垂直滚动条

为了统一交互体验,避免用户误触滚轮导致页面错乱,应将滚动模式设置为无滚动条。

dataGridView1.ScrollBars = ScrollBars.None;

第2步:根据窗体自适应计算每页行数

若表格高度随窗口大小变化,需动态计算当前可视区域内能容纳的最大行数。此计算应在Resize事件中执行,以获取最新的空间尺寸:

int rowCount; // 每一页显示的行数
int maxCount; // 总页数

private void uc_table_Resize(object sender, EventArgs e)
{
    this.Invalidate();
    // 计算可用高度:表格总高度减去列头高度
    int availableHeight = dataGridView1.Height - dataGridView1.ColumnHeadersHeight;
    
    // 计算每页最大行数
    if (dataGridView1.RowTemplate.Height > 0)
    {
        rowCount = availableHeight / dataGridView1.RowTemplate.Height;
    }
    else
    {
        // 兜底逻辑,防止除以零
        rowCount = 10;
    }
    
    // 向上取整计算总页数
    maxCount = (int)Math.Ceiling(dataGridView1.Rows.Count / (double)rowCount);
}

注意:如果表格初始化时已加载大量数据,RowTemplate的高度可能无法正确反映实际渲染高度。此时建议在设置 AutoGenerateColumns 之前或通过调整列头高度来确保 RowTemplate 准确对应实际行高。

第3步:指定起始显示行

核心属性为 FirstDisplayedScrollingRowIndex,它决定了屏幕最上方显示的第一行索引。

// 翻回第一页
dataGridView1.FirstDisplayedScrollingRowIndex = 0;

// 翻至最后一页
int lastRowIndex = Math.Max(0, dataGridView1.Rows.Count - rowCount);
dataGridView1.FirstDisplayedScrollingRowIndex = lastRowIndex;

上述方法通过简单的坐标偏移实现了流畅的切换效果。对于需要频繁跳转的数据操作,建议配合 Refresh() 调用以确保重绘及时。

进阶方案:定时器驱动的数据循环读取

在特定的展示场景(如数据看板、实时监控)下,可能需要数据自动按页轮换。下面提供一个基于 DataSet 和 Timer 的自动翻页示例。该示例假设每页固定显示5行,间隔2秒切换一次。

准备工作:初始化与数据库连接

首先配置窗体加载事件,获取数据总量并计算分页参数:

using System.Data;
using System.Data.SqlClient;
// ... 其他引用

public partial class Form1 : Form
{
    private DataSet myDataSet = new DataSet();
    private int DataRowsCountTotal = 0; // 总行数
    private int PageCount = 0;          // 满页页数
    private int residualRowsCount = 0;  // 剩余行数(最后一页不完整部分)
    private int TakeCount = 0;          // 当前页码(从0开始)

    private void Form1_Load(object sender, EventArgs e)
    {
        // 建议使用配置文件管理连接字符串
        string myConnectString = "Server=localhost;User Id=sa;Pwd=123;DataBase=test";
        using (SqlConnection myConn = new SqlConnection(myConnectString))
        {
            myConn.Open();
            SqlCommand myComm = new SqlCommand("SELECT * FROM Table_1 ORDER BY ID ASC", myConn);
            SqlDataAdapter myAdap = new SqlDataAdapter(myComm);
            myAdap.Fill(myDataSet, "Table_1");
        }

        // 基础数据计算
        DataRowsCountTotal = myDataSet.Tables[0].Rows.Count;
        int PageSize = 5; // 假设每页5行
        PageCount = DataRowsCountTotal / PageSize;
        residualRowsCount = DataRowsCountTotal % PageSize;

        // UI 配置
        dataGridView1.AutoGenerateColumns = false;
        dataGridView1.RowHeadersVisible = false;
        dataGridView1.AllowUserToAddRows = false;

        // 启动定时器
        timer1.Interval = 2000; // 2秒
        timer1.Enabled = true;
        
        // 绑定第一页
        DataGrieDataBind(0);
    }
}

第2步:数据切片与绑定

为了实现“虚拟”的分页而不重新请求数据库,可以将内存中的 DataSet 进行内存级切片。创建一个新的 DataTable 克隆结构并导入指定范围的数据:

private void DataGrieDataBind(int currentPageIndex)
{
    DataTable myDt = new DataTable();
    myDt = myDataSet.Tables[0].Clone(); // 克隆表结构
    
    int pageSize = 5; // 每页行数需与计算时保持一致
    int totalRows = DataRowsCountTotal;
    bool isLastPage = (currentPageIndex + 1 > PageCount);
    
    int startIndex = currentPageIndex * pageSize;
    int endIndex;

    if (isLastPage)
    {
        // 处理最后一页,可能不满5行
        endIndex = totalRows - 1;
    }
    else
    {
        // 处理中间页,共5行
        endIndex = startIndex + pageSize - 1;
    }

    for (int i = startIndex; i <= endIndex && i < totalRows; i++)
    {
        myDt.ImportRow(myDataSet.Tables[0].Rows[i]);
    }

    myDt.AcceptChanges();
    this.dataGridView1.DataSource = myDt;
}

第3步:定时器触发翻页逻辑

在 Timer 的事件处理程序中更新计数器,并在到达末页后重置为首页:

private void timer1_Tick(object sender, EventArgs e)
{
    TakeCount++;
    
    // 判断是否超出总页数
    if (TakeCount > PageCount)
    {
        TakeCount = 0; // 回到第一页
    }
    
    DataGrieDataBind(TakeCount);
}

这种实现方式的优势在于无需频繁读写数据库,所有延迟发生在客户端内存计算中。但需注意,当数据量极大时,整个数据集装入 DataSet 会造成内存溢出,此时应改回第一种手动定位方案或直接优化 SQL 查询。

风险提示与局限性

  • 大数据量性能警告: 将数万甚至更多行数据一次性载入 DataTable/DataSet 会消耗大量内存,并可能导致UI线程阻塞卡顿。对于生产环境的大数据表,强烈建议在 SQL 层面使用 T-SQL 或 OFFSET/FETCH 进行物理分页。
  • 内存碎片: 频繁创建临时 DataTable 对象并绑定 DataSource 可能会引起 GC 压力,高频应用场景可考虑复用 DataTable 实例并清空行后再填充。

总结

C# DataGridView 的分页可以通过控制显示首行索引来实现轻量级的客户端翻页,适用于中小数据量的展示需求;而结合定时器的全量数据切片则更适合大屏循环展示。在处理具体业务时,请根据数据规模选择内存计算还是数据库查询策略,以避免性能瓶颈。 以上就是 C# DataGridView 手动与自动分页控制的详细内容,更多关于 C# 表格控件优化的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。