考虑一下当你填充一个未绑定的对象时会发生什么DataTable
与 a 中的一行DataReader
: A DataRow
被创建,填充自DataReader
,并添加到Rows
收藏。然后,当您创建绑定时,DataGridView
从表中提取数据并在屏幕上构建视图。
当您填充一个时会发生什么DataTable
其绑定到DataGridView
已启用?一团糟的事件处理。每次更改绑定属性时,都会引发属性更改事件并由绑定控件处理该事件。这不是发生了 300,000 次,而是每个都发生了 300,000 次column.
如果您将其关闭并且仅偶尔更新绑定控件会怎么样?看看这个方法:
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
对象,但取出事件是一个重大改进。在我的机器上,如果我填充 10 列、10000 行DataTable
这绑定到DataGridView
,需要2900毫秒。如果我一直关闭数据绑定,则需要 155 毫秒。如果我每 500 行重置一次绑定,则需要 840 毫秒。
当然,如果我要填充 300,000 行表,我不会每 500 行重置一次绑定;我可能会在 500 行标记处执行一次,然后将其关闭,直到操作完成。但即使你这样做,你也需要打电话Application.DoEvents
每隔一段时间,以便 UI 可以响应事件。
Edit
别介意那一点Application.DoEvents
;如果您在后台任务中填充表,则不需要这样做。
但您确实需要确保重置中的绑定BackgroundWorker
's ProgressChanged
事件处理程序,而不是在DoWork
方法。如果你真的让用户这么做,你将会经历一个充满伤害的世界edit绑定中的数据DataGridView
当您在另一个线程上填充其数据源时。