【问题标题】:Loading DataTable Slow When Bound to DataGridView.Datasource绑定到 DataGridView.Datasource 时加载 DataTable 缓慢
【发布时间】:2010-11-11 20:34:21
【问题描述】:

我找遍了所有的地方,但我无法弄清楚这一点。我正在开发一个 Winforms UI,该 UI 正在拉动我需要在 DataGridView 中显示的大量行。我已经阅读了有关限制行数和分页的所有内容,并且绝对没有好方法可以做到这一点。基本上,我正在处理我在 Codeplex 上编写的 SQL Server 2008 扩展事件管理器的 TargetDataViewer 控件。

http://extendedeventmanager.codeplex.com/

我只能根据特定目标及其呈现数据的方式来做些什么。我正在尝试做的是将已从目标读取的数据流式传输到 DataGridView,类似于 Profiler 或 SQL Server Management Studio 在数据流入时显示数据的方式。我重写了很多代码,并有一个 BackgroundWorker 拉数据并将其处理成DataTable。如果我不设置 DataGridView.DataSource = DataTable,我可以在几分钟内将 300K+ 行数据加载到 DataTable 中,它确实运行得很快。一旦我将 DataTable 添加到 DataSource,它就会慢到几乎停止(而不是几分钟,同样的 300K 行可能需要 1/2 小时)。

我知道问题不在于我的处理代码,它特定于绑定到 DataGridView.DataSource,我有计时代码来证明这一点。我不知道如何解决这个问题。对于性能,我可以在加载数据后将控件晚绑定到 DataTable,但这是一种非常糟糕的用户体验。我看到很多人在加载数据时抱怨 DataGridView 性能影响,所以这可能只是我遇到的一个限制?有什么想法吗?

【问题讨论】:

  • 希望我听起来不傻。但是在这种情况下 DataReader 有帮助吗?
  • 不,我有一个打开的 SqlDataReader,它为每一行提取一个非模式绑定的 XML 文档。然后我有将这个 XML 解析成一个 object[] 的代码,该 object[] 作为参数传递给 LoadRow() 方法。

标签: c# winforms datagridview c#-3.0


【解决方案1】:

想一想当您使用来自DataReader 的一行填充未绑定的DataTable 时会发生什么:创建DataRow,从DataReader 填充,并添加到Rows 集合中。然后,当您创建绑定时,DataGridView 从表中提取数据并在屏幕上构建视图。

当您填充已启用与DataGridView 绑定的DataTable 时会发生什么?一团糟的事件处理。每次更改绑定属性时,都会引发 property-changed 事件并由绑定控件处理它。这不是发生 300,000 次,而是每个 发生 300,000 次。

如果您将其关闭,并且只偶尔更新绑定控件会怎样?看看这个方法:

private void PopulateDataTable()
{
    int rowCount = 10000;

    bindingSource1.RaiseListChangedEvents = false;
    for (int i = 0; i < rowCount; i++)
    {
        DataRow r = DT.NewRow();
        for (int j = 0; j < ColumnCount; j++)
        {
            r[j] = "Column" + (j + 1);
        }
        DT.Rows.Add(r);

        if (i % 500 == 0)
        {
            bindingSource1.RaiseListChangedEvents = true;
            bindingSource1.ResetBindings(false);
            Application.DoEvents();
            bindingSource1.RaiseListChangedEvents = false;
        }
    }
    bindingSource1.RaiseListChangedEvents = true
}

你必须调用 ResetBindings 来强制更新绑定的控件。这需要时间,因为您无法绕过构建DataGridViewRow 对象的成本,但取出事件是一项重大改进。在我的机器上,如果我填充绑定到 DataGridView 的 10 列、10000 行 DataTable,则需要 2900 毫秒。如果我一直关闭数据绑定,则需要 155 毫秒。如果我每 500 行重置一次绑定,则需要 840 毫秒。

当然,如果我要填充 300,000 行的表,我不会每 500 行重置一次绑定;我可能会在 500 行标记处执行一次,然后将其关闭,直到操作完成。但即使你这样做了,你也需要每隔一段时间调用一次Application.DoEvents,以便 UI 可以响应事件。

编辑

没关系Application.DoEvents;如果您在后台任务中填充表格,则不需要这样做。

但您确实需要确保在BackgroundWorkerProgressChanged 事件处理程序中重置绑定,而不是在DoWork 方法中。如果您在另一个线程上填充其数据源时,实际上让用户编辑绑定DataGridView 中的数据,那么您将经历一个痛苦的世界。

【讨论】:

  • 你我的好先生,现在是我今天的英雄。这正是我所需要的,并且工作得很好。我编写了一个自定义分类器方法,该方法返回一个布尔值,用于判断 BindingSource 是否应根据 DataTable 中的当前数据量进行更新,以便它在早期刷新以更快地呈现行,并且随着数据的增加而变慢以尝试平衡刷新与性能。它并不完美,但比以前好多了。
  • 很高兴听到这个消息。不过,我认为您仍然可能在将 UI 控件绑定到包含 30 万条记录的数据源时遇到很多麻烦。尝试使用 DataGridView 的有限工具管理这似乎是一个疯狂的数据量。
猜你喜欢
  • 2020-04-26
  • 1970-01-01
  • 2013-04-07
  • 1970-01-01
  • 1970-01-01
  • 2018-07-06
  • 2018-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多