C# 绑定到DataGridView.Datasource时加载DataTable速度较慢

C# 绑定到DataGridView.Datasource时加载DataTable速度较慢,c#,winforms,datagridview,c#-3.0,C#,Winforms,Datagridview,C# 3.0,我找遍了,找不出这个。我正在处理一个Winforms UI,该UI正在提取需要在DataGridView中显示的大量行。我已经阅读了所有关于限制行数和分页的内容,但对于我来说,绝对没有什么好方法可以做到这一点。基本上,我正在处理我在Codeplex上编写的SQL Server 2008扩展事件管理器的TargetDataViewer控件 我仅限于根据具体目标以及它如何呈现数据,我能做些什么。我试图做的是将从目标读取的数据流式传输到DataGridView,类似于Profiler或SQL Ser

我找遍了,找不出这个。我正在处理一个Winforms UI,该UI正在提取需要在DataGridView中显示的大量行。我已经阅读了所有关于限制行数和分页的内容,但对于我来说,绝对没有什么好方法可以做到这一点。基本上,我正在处理我在Codeplex上编写的SQL Server 2008扩展事件管理器的TargetDataViewer控件

我仅限于根据具体目标以及它如何呈现数据,我能做些什么。我试图做的是将从目标读取的数据流式传输到DataGridView,类似于Profiler或SQL Server Management Studio在数据流式传输时显示数据的方式。我重写了很多代码,并让一名后台工作人员将数据拉入数据表并进行处理。如果我不设置DataGridView.DataSource=DataTable,我可以在几分钟内将300K+行数据加载到DataTable中,它运行得非常快。一旦我将DataTable添加到数据源,它就会慢到几乎停止(而不是几分钟,同样的300K行可能需要1/2小时)


我知道问题不在于我的处理代码,而在于绑定到DataGridView.DataSource,我有计时代码来证明这一点。我想不出怎么避开这件事。为了提高性能,我可以在加载数据后将控件延迟绑定到DataTable,但这是一种非常糟糕的用户体验。我看到很多人抱怨加载数据时对DataGridView性能的影响,所以这可能是我一直受到的限制?有什么想法吗?

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

当您填充一个与
DataGridView
绑定已启用的
DataTable
时会发生什么情况?一大堆的事件处理。每次更改绑定属性时,都会引发property changed事件,绑定控件将处理该事件。这不是发生30万次,而是每列发生30万次

如果关闭此选项,并且仅偶尔更新绑定控件,会怎么样?看看这个方法:

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
}
private void PopulateDataTable()
{
int rowCount=10000;
bindingSource1.RaiseListChangedEvents=false;
对于(int i=0;i
您必须调用ResetBindings来强制更新绑定控件。这需要时间,因为您无法规避构建
DataGridViewRow
对象的成本,但是删除事件是一个显著的改进。在我的机器上,如果我填充一个绑定到
DataGridView
的10列10000行
DataTable
,则需要2900毫秒。如果我一直关闭数据绑定,则需要155毫秒。如果每500行重置一次绑定,则需要840毫秒

当然,如果我填充300000行表,我不会每500行重置一次绑定;我可能会在500行标记处执行一次,然后关闭它,直到操作完成。但即使这样做,也需要经常调用
Application.DoEvents
,以便UI能够响应事件

编辑

不要介意关于
应用程序的那一点。DoEvents
;如果在后台任务中填充表,则不需要这样做


但是您确实需要确保在
BackgroundWorker
ProgressChanged
事件处理程序中重置绑定,而不是在
DoWork
方法中重置绑定。如果你在另一个线程上填充数据源时,让用户在绑定的
DataGridView
中编辑数据,你会受到很大的伤害。

希望我听起来不那么愚蠢。但是DataReader在这种情况下有用吗?不,我有一个开放的SqlDataReader,它为每一行提取一个非模式绑定的XML文档。然后我有代码将这个XML解析成一个对象[],作为参数传递给LoadRow()方法。这正是我所需要的,而且工作得非常完美。我编写了一个自定义分类器方法,返回BindingSource是否应根据DataTable中的当前数据量进行更新的布尔值,以便它在呈现行之前刷新得更快,在数据增加时刷新得越慢,以尝试平衡刷新与性能。它并不完美,但比以前好多了。很高兴听到这个消息。但是,我认为,如果用户界面控件绑定到一个包含300K条记录的数据源上,您可能仍然会遇到很多问题。用DataGridView有限的工具管理的数据量似乎太多了。