Bootstrap

Datagridview 更换数据时如何防止Paint异常

在使用 DataGridView 控件时,如果频繁更改数据或者进行大量数据更新操作,可能会遇到 Paint 异常或性能问题。

每次更新都会导致 Grid 发生重绘;而当数据更新速度非常快或者其它原因,导致 UI 线程来不及绘制完毕 DataGrid 时,Grid 就会发生绘制错误。

这是因为每次数据发生变化时,DataGridView 都会尝试重新绘制自己以反映最新的状态。为了避免这些问题,可以采取以下几种方法来优化 DataGridView 的行为:

1. 暂停和恢复布局

通过调用 SuspendLayout()ResumeLayout() 方法,可以在批量修改控件属性或添加多个子控件时暂停和恢复布局逻辑,从而减少重绘次数。

在更换数据之前,可以尝试清除DataGridView的现有数据,然后再设置新的数据源,例如使用DataGridView.Rows.Clear()来清除行,然后再设置DataGridView.DataSource

 

Csharp

深色版本

dataGridView1.SuspendLayout();
try {
    // 批量更改数据代码
} finally {
    dataGridView1.ResumeLayout();
}

2. 暂停和恢复绑定

如果你的数据源是通过数据绑定的方式与 DataGridView 关联的,可以通过暂停和恢复绑定来避免不必要的刷新。

 

Csharp

深色版本

BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = yourDataSource;

// 暂停绑定
bindingSource.RaiseListChangedEvents = false;
try {
    // 更改数据源内容
} finally {
    // 恢复绑定并刷新界面
    bindingSource.RaiseListChangedEvents = true;
    bindingSource.ResetBindings(false);
}

3. 使用虚拟模式(Virtual Mode)

对于非常大的数据集,启用 DataGridView 的虚拟模式 (VirtualMode) 可以显著提高性能。在这种模式下,你需要手动管理数据,并处理 CellValueNeeded 事件来提供单元格的内容。这允许你只加载可见部分的数据,而不是整个数据集。

 

Csharp

深色版本

dataGridView1.VirtualMode = true;
dataGridView1.CellValueNeeded += DataGridView1_CellValueNeeded;

private void DataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) {
    // 实现获取值的逻辑
}

4. 禁用自动调整大小

确保没有启用行或列的自动调整大小选项,因为这些选项会在每次数据变化时触发额外的计算和重绘。

 

Csharp

深色版本

dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;

5. 减少无效化区域

尽量减少对 DataGridView 的无效化(Invalidate)调用次数,避免不必要的重绘。如果必须使控件失效,请尽可能精确地指定需要重绘的区域。

6. 设置 DoubleBuffered 属性

虽然 DataGridView 默认启用了双缓冲,但在某些情况下设置此属性为 true 仍有助于改善闪烁问题。需要注意的是,这个属性不是公开的,所以你需要创建一个继承自 DataGridView 的类来访问它。

 

Csharp

深色版本

public class BufferedDataGridView : DataGridView {
    public BufferedDataGridView() {
        this.DoubleBuffered(true);
    }

    protected override bool DoubleBuffered {
        get { return base.DoubleBuffered; }
        set { base.DoubleBuffered = value; }
    }
}

7. 数据更新策略

尽量一次性更新所有要改变的数据,而不是逐个更新每一项。例如,将所有新数据放入一个新的列表中,然后替换现有的数据源,而不是逐一添加或移除项目。

8. 考虑异步加载数据

对于大型数据集,考虑使用异步方式加载数据,这样可以在不影响UI响应性的前提下逐步显示数据。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;