2

我有一个绑定到 BindingSource 的 WinForms DataGridView,而后者又绑定到 100,000 个对象的 BindingList。

BindingList<MyObject> myObjectList = new BindingList<MyObject>();
BindingSource bindingSourceForMyObjects = new BindingSource();

bindingSourceForMyObjects.DataSource = myObjectList;
dataGridViewMyObjects.DataSource = bindingSourceForMyObjects;

我有一个事件处理程序连接到我的 DataGridView 的 CellValueChanged 事件,其中包含以下代码:

dataGridViewMyObjects.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red;
dataGridViewMyObjects.Rows[e.RowIndex].DefaultCellStyle.ForeColor = Color.White;

因此,当我的用户更改一行时,此事件处理程序会触发并将该行更改为红底白字,以指示数据已更改。这很好用,但在某些情况下,我需要以编程方式更改基础列表,并且我希望这些更改也反映在 DataGridView 中。为此,我的对象类实现了 INotifyPropertyChanged,并且我有一个连接到我的 BindingSource 的 ListChanged 事件的事件处理程序。该事件处理程序中的代码如下所示:

if (e.ListChangedType == ListChangedType.ItemChanged)
{
    dataGridViewMyObjects.Rows[e.NewIndex].DefaultCellStyle.BackColor = Color.Red;
    dataGridViewMyObjects.Rows[e.NewIndex].DefaultCellStyle.ForeColor = Color.White;
}

这也有效,因此如果我以编程方式修改 50 个对象,DataGridView 行也会更新。但是,正如我之前所说,我正在处理 100,000 个对象,如果我需要修改超过 800 个对象,则可能需要一段时间,因为我的对象中对 OnPropertyChanged() 的所有调用。在绝对最坏的情况下,如果我需要修改所有 100,000 个对象,这可能需要将近 1 分钟才能发生。

在我的对象类中,我有一个布尔变量,当我以编程方式执行“批量”更新(> 800 个对象)时,我使用它来避免触发 OnPropertyChanged() 调用。这使得更新对象属性非常快,但 DataGridView 中的相应行不再更新它们的前景色/背景色值,因为双向绑定被绕过。我知道哪些行对应于已修改的对象,并且我尝试遍历它们并更新 ForeColor/BackColor 值,但同样,此操作需要将近一分钟才能完成。

我试过把那个循环包装在......

dataGridViewMyObjects.SuspendLayout();
// loop here
dataGridViewMyObjects.ResumeLayout();

但这似乎并没有对性能产生影响。是否有更快的方法来为大量行设置 ForeColor/BackColor 或者我看到的速度仅仅是我正在使用的数据大小的问题?

4

1 回答 1

2

要尝试的一件事是告诉 Windows 在循环更改更改时停止绘制控件。从如何暂停控件及其子控件的绘制?

class DrawingControl
{
    [DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);

    private const int WM_SETREDRAW = 11; 

    public static void SuspendDrawing( Control parent )
    {
        SendMessage(parent.Handle, WM_SETREDRAW, false, 0);
    }

    public static void ResumeDrawing( Control parent )
    {
        SendMessage(parent.Handle, WM_SETREDRAW, true, 0);
        parent.Refresh();
    }
}

然后您的代码将如下所示:

DrawingControl.SuspendDrawing(dataGridViewMyObjects);
// loop here
DrawingControl.ResumeDrawing(dataGridViewMyObjects);
于 2013-01-24T17:10:24.753 回答