You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DataGridView逐行设置DefaultCellStyle运行异常缓慢问题排查

为什么你的DataGridView样式设置这么慢?

首先,这种速度肯定不正常——处理5000行花几十分钟完全是可以优化的,核心问题出在你直接操作DataGridView的UI行对象,以及一些可以避免的重复开销上。

慢的核心原因

你当前的代码是遍历DataTable的行,然后直接操作dataGridView1.Rows[r]这个UI控件对象。哪怕用了SuspendLayout(),每次访问DataGridView的Row集合都会触发底层的UI控件逻辑,5000次这样的操作累积起来开销巨大。另外,你每次循环都重复访问dbInterface.ds.Tables["articles"],这也会增加不必要的属性访问开销。

优化方案:从一次性全量处理改为按需绘制

最有效的优化是利用DataGridView的RowPrePaint事件,它只会在绘制可见行的时候触发,不需要一次性处理所有5000行,性能会提升几个数量级。

步骤1:提前定义样式(作为类级变量)

把样式对象移到类的顶部,避免每次函数调用都重新创建:

private DataGridViewCellStyle _groupCellStyle;
private DataGridViewCellStyle _subTotCellStyle;

// 在窗体构造函数或者初始化方法里初始化样式
public YourForm()
{
    InitializeComponent();
    InitCellStyles();
}

private void InitCellStyles()
{
    _groupCellStyle = new DataGridViewCellStyle();
    _subTotCellStyle = new DataGridViewCellStyle();
    
    _groupCellStyle.Font = new Font(dataGridView1.Font, FontStyle.Bold);
    _groupCellStyle.BackColor = Color.FromArgb(235, 235, 235);
    _subTotCellStyle.BackColor = Color.FromArgb(155, 155, 255);
}

步骤2:注册RowPrePaint事件,按需设置样式

取消原来的formatRows()函数,改用事件处理:

// 在窗体加载或者数据绑定完成后注册事件
private void YourForm_Load(object sender, EventArgs e)
{
    dataGridView1.RowPrePaint += DataGridView1_RowPrePaint;
    // 这里加上你的数据绑定逻辑
}

private void DataGridView1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
    // 跳过新行(如果启用了AllowUserToAddRows)
    if (e.RowIndex == dataGridView1.NewRowIndex)
        return;
    
    // 缓存DataTable,避免重复访问
    var dt = dbInterface.ds.Tables["articles"];
    short flgGroup = dt.Rows[e.RowIndex].Field<short>("FLGGroup");
    
    DataGridViewCellStyle targetStyle = null;
    if (flgGroup == 2)
        targetStyle = _groupCellStyle;
    else if (flgGroup == 0)
        targetStyle = _subTotCellStyle;
    
    if (targetStyle != null)
    {
        dataGridView1.Rows[e.RowIndex].DefaultCellStyle = targetStyle;
    }
}

步骤3:开启DataGridView的性能优化开关

再给DataGridView加上几个性能提升的设置,进一步加速:

// 在窗体初始化时添加这些设置
private void InitDataGridViewSettings()
{
    // 关闭自动列宽(如果不需要动态调整)
    dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
    // 关闭自动行高
    dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
    // 关闭行头(如果不需要)
    dataGridView1.RowHeadersVisible = false;
    // 开启双缓冲(通过反射设置,因为它是保护属性)
    typeof(DataGridView).InvokeMember(
        "DoubleBuffered",
        BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
        null,
        dataGridView1,
        new object[] { true }
    );
}

如果你坚持要一次性设置所有行

如果必须一次性处理完所有行,那至少要优化循环逻辑,减少UI交互开销:

private void FormatRowsOptimized()
{
    var dt = dbInterface.ds.Tables["articles"];
    int rowCount = dt.Rows.Count;
    
    dataGridView1.SuspendLayout();
    // 关闭重绘
    dataGridView1.Visible = false;
    
    for (int r = 0; r < rowCount; r++)
    {
        short flgGroup = dt.Rows[r].Field<short>("FLGGroup");
        if (flgGroup == 2)
            dataGridView1.Rows[r].DefaultCellStyle = _groupCellStyle;
        else if (flgGroup == 0)
            dataGridView1.Rows[r].DefaultCellStyle = _subTotCellStyle;
    }
    
    dataGridView1.Visible = true;
    dataGridView1.ResumeLayout();
}

这里加上dataGridView1.Visible = false可以避免循环过程中的UI重绘,比单纯用SuspendLayout()效果更好。

最后说两句

5000行36列的DataGridView本身不算特别大,优化后应该能在几秒内完成样式设置。优先用RowPrePaint事件的方案,因为它是按需处理,内存和性能都更友好。

内容的提问来源于stack exchange,提问作者MonkeyH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:18:23