C#填充DataGridView速度非常慢

17

我正在使用DataTable填充DataGridView。

在填充列和行的同时,我还进行了格式化操作,这导致DataGridView加载非常缓慢,是否有解决此问题的方法?


你有格式化的代码示例吗?你要加载多少数据到网格中?你使用分页数据源还是将所有数据都加载到网格中? - Ivo
你能否发布用于填充DataGridView的代码?你是否已将DataGridView与DataTable绑定,还是在DataTable中进行迭代并将记录插入DataGridView中? - aleroot
11个回答

13

除了处理AutoSizeColumnsMode外,还要确保各个列的AutoSizeMode属性也被设置为除了所有单元格之外的其他选项。

我还发现需要使用

SendMessage(dg.Handle, WM_SETREDRAW, false, 0); // before

// updates to datagridview here...

SendMessage(dg.Handle, WM_SETREDRAW, true, 0); // after

2
在刷新数据源之前将AutoSizeColumnsMode更改为None,然后在设置数据源后将其设置回All,这样可以将我的加载时间从几分钟降至不到一秒钟。 - KevenDenen

10

使用它后,DataGridView将像Java JTable一样快速 :)

public static class ExtensionMethods
{
    public static void DoubleBuffered(this DataGridView dgv, bool setting)
    {
        Type dgvType = dgv.GetType();
        PropertyInfo pi = dgvType.GetProperty("DoubleBuffered",
            BindingFlags.Instance | BindingFlags.NonPublic);
        pi.SetValue(dgv, setting, null);
    }
}

ExtensionMethods.DoubleBuffered(dataGridView1, true);

7

我之前加载1-2k行数据需要2-4分钟的时间。我改变了自动调整大小的属性,现在只需要10-20秒就能完成。我在创建行的循环之前运行了这个操作以确保它获取了所有的列。

foreach (DataGridViewColumn c in thisGrid.Columns)
{
    c.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
}

6
你可以检查DataGridView的属性-AutoSizeColumnsMode,我发现如果将模式从AllCells更改为DisplayedCells,则性能会有所不同。希望这能帮到你。

3
当您使用数据网格视图从数据库显示数据时,应该始终考虑使用一些策略来限制结果集并仅在用户实际查看它们时显示记录。这有时被称为虚拟模式或数据分页。我找到了一个用于wpf的此策略示例,但也有适用于winforms的内容。请参考这个问题:Winform DataGridview比MS Access Grid慢得多,我认为这也与您的问题有关。

同意,当有人谈论数据网格的缓慢时,通常是因为要读取成千上万行数据才能显示出10行。确保你正在分页读取数据。(又称:数据分页) - detay
1
@detay 是的,拥有快速的网格的魔力不在于填充网格的速度有多快,而是避免去填充它 :D - Felice Pollano

1
一个愚蠢的老家伙的规则: - 避免使用DataTable,因为它被认为是低效的 - 避免使用行的预分配["Grid".RowCount + "Grid".AddRange() +..](比"Grid"ADD()慢约5倍) - 考虑到DataGridView绑定到“您的屏幕”:即用少量数据加载它。 - 我应用了这些简单的事实,我可以在15秒内“加载”一个420,000行,159列的“愚蠢文件”(约200 MB)。

0

对我来说,问题在于ColumnHeadersHeightSizeMode属性,所以我建议使用以下代码片段,其中包含其他回答者提出的一些建议。这样做的优点是,如果您的网格没有以某种方式自动调整大小,则不会盲目地恢复到AutoSize:

private static void FastLoadDataGrid<T>(DataGridView dgv, IEnumerable<T> objList)
{
    // Cache old values
    DataGridViewAutoSizeColumnsMode oldAutoSizeCols = dgv.AutoSizeColumnsMode;
    DataGridViewAutoSizeRowsMode oldAutoSizeRows = dgv.AutoSizeRowsMode;
    DataGridViewRowHeadersWidthSizeMode oldRowHeader = dgv.RowHeadersWidthSizeMode;
    DataGridViewColumnHeadersHeightSizeMode oldCol = dgv.ColumnHeadersHeightSizeMode;

    dgv.SuspendLayout(); // off for performance 

    // switch off stuff for performance
    dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None; 
    dgv.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None; 
    dgv.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;
    dgv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;

    // flush and load data source 
    dgv.DataSource = null;
    dgv.DataSource = new List<T>(objList); //wrap in sortable bindinglist to allow user to sort via column header click

    // revert back to old values
    dgv.AutoSizeColumnsMode = oldAutoSizeCols;  
    dgv.AutoSizeRowsMode = oldAutoSizeRows; 
    dgv.RowHeadersWidthSizeMode = oldRowHeader;
    dgv.ColumnHeadersHeightSizeMode = oldCol;

    dgv.ResumeLayout(false); // turn back on
}

调用此过程的典型方法是:

FastLoadDataGrid(MyDataGridView, MyListOfCustomers);

通过使用我的 FastLoadDataGrid,导入 3 列 10000 行的测试数据,并在数据网格视图中显示每个成功数据的时间从 8 秒缩短到了 3 秒。

微软提供的其他建议包括: DataGridView 优化

另一种完全不同的方法是使用虚拟化。打开 VirtualMode = true。但这可能需要重构绑定数据事件。请参见: DataGridView 虚拟化


0

我遇到了同样的问题,在我的情况下,我还需要设置 DataGridView.RowHeadersWidthSizeMode = DisableResizing


0

我在一个程序中进行了一些测试,其中我加载了5000行6列的数据,每个单元格都加载了行号以获得一些数据。然后我使用了Stopwatch来测试每种方法。我加载了dataviewgrid,禁用它并加载它,然后启用它,隐藏它,加载它,显示它,以及suspendlayout和resumelayout。我发现,在我的测试中,隐藏它,然后加载它,再显示它要快得多。它花费了: 仅加载需要0.91秒 suspendLayout、加载和resumeLayout需要0.91秒 禁用、加载和重新启用网格需要0.25秒 隐藏、加载和显示网格需要0.19秒。

我同意你应该避免加载不需要的内容,但我认为这个测试会有所帮助。


0

这是我发现有效的方法。我正在构建一个52x15网格,具有自定义单元格着色,并且使用上面的所有建议生成和显示需要10-20秒的时间,但并没有显著提高性能。

现在这个更改使它在大约1秒内显示,同时使用了双缓冲技术。

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

然后在生成数据完成之后

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接