使用最佳方法填充包含大量数据的DataGridView

23

我有一个Windows表单,其中有两个DataGridView(DGV),每个DGV将容纳25000多条记录和21列。 我已经使用DataAdapter成功地从数据库中加载了数据,并尝试使用for循环简单地填充DGVs。 每种方法大致需要相同的时间。 第一次将数据填充到DGVs中需要太长时间(7分钟以上),然后随后的时间就会更合理(约30秒)。 那么我的问题是,最佳方法是用平均不超过1分钟来加载大量数据的DGV? 我真的很喜欢DGV的功能,但如果必要,我愿意使用其他技术,即使这意味着放弃某些功能。


5
你知道虚拟模式吗?它不会加载所有的数据,DGV会告诉你“我需要146-203行的记录”,然后你只获取这些行。http://msdn.microsoft.com/en-us/library/15a31akc.aspx - Jonathan
谢谢Jonathan!听起来就是我需要的。然而,我有一个问题。应用程序的下一步是比较两个DGVs。当以编程方式进行比较时,我是否仍然可以访问整个数据集? - Bkins
6个回答

37

DataGridView 中,基本上有三种显示数据的方法:

  • 手动使用循环创建行,就像您当前正在做的一样:正如您已经注意到的那样,如果数据量很大,这种方法非常低效。

  • 使用 DataGridView 的虚拟模式,如Jonathan在评论中建议的那样:DGV 仅创建可显示的行数,并在用户滚动时动态更改其内容。 您需要处理 CellValueNeeded 事件以向 DGV 提供所需的数据。

  • 使用数据绑定:这是迄今为止最简单的方法。 您只需使用 DbDataAdapter 从数据库中填充数据到 DataTable 中,并将此 DataTable 分配给 DGV 的 DataSource 属性。 DGV 可以自动创建列(AutoGenerateColumns = true),或者您可以手动创建它们(必须将列的 DataPropertyName 设置为要显示的字段的名称)。 在数据绑定模式下,DGV 的工作方式类似于虚拟模式,除了它负责从数据源获取数据,因此您无需执行任何操作。 即使对于大量行,它也非常高效。


7
如果您有大量行数据,例如10,000行或更多,
为避免性能泄漏 - 在绑定数据之前,请执行以下操作:
dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing; 
//or even better .DisableResizing. 
//Most time consumption enum is DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders
dataGridView1.RowHeadersVisible = false; // set it to false if not needed

数据绑定后,您可以启用它。

1
我知道回复已经很晚了,但经过近一个星期的努力,在你告诉我的设置中解决了我的问题...愿你长命百岁 :) - TheSacredKiller
仍然在2021年保持相关性...不自动调整列大小可以节省大量时间...谢谢。 - MX313

6

我认为您可以使用DataReader方法代替DataAdapter。DataReader是一个高效的单向组件,因为它只从源中读取数据,并可以通过循环填充数据表。


3
尝试使用DataTable。将其填充。 然后使用DataView。将其分配给DataGridView的数据源。
//DataView dataView = new DataView(dataTable);
//this.Grid.DataSource = dataView;

对于大文件(25000条记录和21列),您将获得非常短的响应时间,每秒可达到。我的模板程序需要7秒钟才能加载100,000行* 100列,其中包含愚蠢的内容(使用字符串表示行号)。


我刚刚使用了10列,6753行进行了测试,用时2:03.9174603 6735。我使用的表单非常简单,除了一个按钮来初始化填充datagridview之外,没有其他控件。 - dmoore1181
请添加更改(“DataView”)前后所需的时间,以便我们比较实际差异有多大。 - AL - Lil Hunk

1
这解决了我的问题:

array<DataGridViewRow^>
    ^theRows = nullptr;
if (DG->Rows->Count == 0)//First Compilation
{
    int NUMROWS = xxx;
    theRows = gcnew array<DataGridViewRow^>(NUMROWS);
    for (int nr = 0; nr < DRH->Count; nr++)
        theRows[nr] = gcnew DataGridViewRow();
//Do not remove the two following
    DG->Rows->AddRange(theRows);
    DG->Rows->Clear();
}
else //Update
{

    theRows = gcnew array<DataGridViewRow^>(DG->Rows->Count);
    DG->Rows->CopyTo(theRows, 0);
    DG->Rows->Clear();

}
for(int nr=0;nr<theRows->Length;nr++)
{
    theRows [nr]->SetValues("val1", "val2");
}
DG->Rows->AddRange(theRows);

0

我不确定这是否完全符合您的要求,但我喜欢创建一个数据子集来进行初始加载,然后包括搜索功能。 使用Visual Studio 15和DataSources / data sets非常容易实现。 在解决方案资源管理器中,打开您的dataset.xsd文件。它将被命名为DataSet.xsd 进入相关的数据表。右键单击并添加查询。我通常做的一件事是只需在我的查询中添加“TOP 1000”。 因此,选择* from mytable变成了select TOP 1000 * from mytable

最后,双击您的窗体以找到_load方法,并更改“Fill”以使用您的新查询。这可能最好通过示例演示:

我注释掉的第一行代码是Vis Stud默认创建的内容。 第二个是我添加的,它将仅获取前1000条记录。

        private void Form_Customers_Load(object sender, EventArgs e)
    {
        // TODO: This line of code loads data into the 'stage2DataSet.customers' table. You can move, or remove it, as needed.
        /* this.customersTableAdapter.Fill(this.stage2DataSet.customers); */
        this.customersTableAdapter.FillBy_Top_1000(this.stage2DataSet.customers);


    }

我真的反对使用未经类型化的数据集。 a) 那个查询会起作用,但是当您稍后更新数据集时,特别是随着数据库的增长并且开始变得难以在数据集设计器中找到特定查询时,它将覆盖所有查询并重置为默认查询。因此,您必须不断重新创建这些用户定义的查询。 b) 它们还要求您在编写代码之前在每个地方填充TableAdapters,这可能非常缓慢。 - Hannington Mambo

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