DataGrid重绘速度慢

5
我正在使用System.Windows.Forms.DataGrid。它有大约3000行数据,重绘速度非常慢。如果我最小化和最大化我的窗体,所有其他控件都会显示,但我却要看着DataGrid逐行重绘。这个DataGrid中的所有内容都是只读的,如果这有所区别的话。
更新:
我不确定如何为我的项目正确地实现CellValueNeeded()事件,或者它是否会对我的DataGrid性能有所帮助。
我正在创建一个包含DataGridView的用户控件(请参见下面的代码)。当调用SetProject()方法时,我的控件被设置为特定的Project类实例。然后,控件使用静态方法Informa.Data.GetProjectDataTable(Project proj)从Project中提取一个DataTable。然后将DataGrid的DataSource属性设置为返回的DataTable。
这是我第一次使用ADO或DataGrids,所以请多多包涵。看起来CellValueNeed()允许我覆盖DataGrid找到其单元格值的方式,但在我的情况下,这比MSDN上的示例复杂得多。实际数据源是各种节点对象的树结构,其根是Project实例。每个节点可以具有一组可变属性,这些属性也可以在运行时由用户扩展。然后,还有一堆其他复杂性,例如节点从其父节点继承属性值,并从其子节点累加其他属性值。
Informa.Data.GetProjectDataTable()穿越所有这些疯狂的东西,并生成一个包含所有节点属性的单个平面DataTable。在这一点上,我不关心能否将此表的任何更改与原始树结构相关联,或者在树结构更改时更新表的特定部分。我只想在DataGrid中向用户显示数据。
那么我是否要实现CellValueNeeded()以从Project提供的DataTable中读取数据?我认为DataGrid应该已经知道如何有效地使用DataTable作为DataSource?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Informa;

namespace Informa
{
public partial class ProjectGridControl : UserControl
{
    private Project proj;

    public ProjectGridControl()
    {
        InitializeComponent();
    }

    public void SetProject(Project proj)
    {
        this.proj = proj;
        UpdateGridControl();
    }

    public void UpdateGridControl()
    {
        if (this.proj == null)
        {
            this.dataGrid.DataSource = null;
        }
        else
        {
            //Extracts a DataTable from the project and sets it as the 
            //DataSource of the property grid
            this.dataGrid.DataSource = Informa.Data.GetProjectDataTable(proj);
        }
    }
}

}


建议您发布一些(简化的)代码... - Mitch Wheat
哪些事件正在触发?你处理了哪些事件?如果你有在每个列/行/单元格上运行的代码,我会在那里进行检查。 - John B
我没有处理任何事件。我正在创建一个 DataTable 并将其设置为 DataGrid 的数据源。就这样。 - Eric Anastas
5个回答

10
曾经有只名叫MacroSoft的小狼和绵羊Vidia在一起,他们制作了地球上最慢的文本和网格渲染,并将所有工作都推到了CPU上,在硬件进步的繁荣年代;而绵羊则确保它变得更加缓慢。

如果我说得对,你欠这些人一封信 :-)

你正在运行NVidia卡和他们的垃圾驱动程序或类似的东西,同时看到MSFT拒绝修复GDI+以实现硬件加速,与友好的供应商一样(甚至Mono会在他们决定给您一些节能和适当的硬件重用之前就完成它;您知道像样的工程)。

将您的DataGridView包装成一个新类型(即继承)并将其DoubleBuffered属性设置为true,更改设计器代码以使用该新类型。

可见的“逐行”渲染说明这个行业在2009/2010年是多么糟糕,有超级计算机的台式机和单个DLL,一个大公司拒绝修复但很高兴为其执行而收费使其在Mounta-Dismounta-Vista上运行得更慢。小丑们..


2
是的,将双缓冲设置为true似乎已经解决了问题。谢谢。 - Eric Anastas
3
类DBDataGridView继承自System.Windows.Forms.DataGridView,构造函数中设置DoubleBuffered为true。 - Zsolti
我正在使用BindingSource填充DataGridView。 我大约有1000条记录。 我使用了DoubleBuffered属性并将其设置为true。 但是仍然非常缓慢。 - VJOY

5
你是否开启了列的自动调整大小?即使只有10行数据,用户在我们的应用程序中体验到了巨大的减速。基本上,一个网格允许用户选中/取消一个框以将一行添加到另一个网格中,而第二个网格会随着每添加一行而经历指数级的减速。
经过一些分析,我发现向第二个表中添加5行需要大约12秒钟的时间。最后尝试关闭列的自动调整大小功能,现在已经瞬间完成。

不过谢谢你的建议,我们没有对行和列进行自动调整大小。 - Eric Anastas
@Chris Doggett:谢谢,谢谢,谢谢!!!调试了1.5小时后,终于找到了你的帖子。现在选择一行运行速度快了约500%;-) - andzep
你好。请问如何关闭 AutoSize?我找不到相关文档。谢谢。 - Yisroel M. Olewski
精辟的观察!有趣的是这会产生如此大的差别。 - poy

4

我曾经遇到一个很大的问题,就是datagridview非常缓慢。我需要将其尽可能地放大在屏幕上,但似乎它的物理大小对绘制速度的影响比数据量等因素更大。对我真正起作用的是设置CellBorderStyle=None(显然每个单元格负责绘制自己的边框,这似乎很荒谬,因为单元格边框在屏幕上保持不变,所以每个单元格都不需要不停地重绘自己的边框来滚动,但无论如何...)。

现在,没有单元格边框的网格并不是一个好的网格。但幸运的是,您可以为列和行均设置DividerWidth。这些值默认为0,但将它们设置为1(或更高,如果您想要更厚的边框),将使您回到与CellBorderStyle=Single相同外观的“单元格”边框,但这一次会“静态”绘制整个datagridview。

此外,如果有许多行,请将AutoResize属性设置为False。

在我的情况下,绘制速度的改善非常巨大。


很好的观察!我已经开启了虚拟模式,但没有什么帮助(我有一个20x7的网格,在定时器上每20毫秒更新3次)。但这个方法显着改善了性能。 - Alex
如果你尝试了双缓冲解决方案,那么你还需要这个解决方案吗? - Dan W

2

0
在Visual Studio 2015中,如果将2个DataGridView的AutoSize列设置为None,但是有...
dgv1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders;

这是导致行添加非常缓慢和用户列调整大小问题的原因。

因此,如果我将上面的行 REM 掉,UX现在就很快了。请参见{{link1:AutoSizeRowsMode}},并且可能存在与{{link2:AutoSizeColumnsMode}}相同的问题。


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