【问题标题】:Fastest way to set backcolor for WinForms DataGridView rows为 WinForms DataGridView 行设置背景颜色的最快方法
【发布时间】:2013-01-24 14:56:08
【问题描述】:

我有一个绑定到 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,或者我看到的速度仅仅是我正在使用的数据大小的问题?

【问题讨论】:

标签: c# winforms data-binding datagridview


【解决方案1】:

要尝试的一件事是告诉 Windows 在循环执行更改时停止绘制控件。来自How do I suspend painting for a control and its children?

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);

【讨论】:

  • 在我的情况下,这会使着色稍微快一些;还有其他需要解决的减速问题,但它们超出了这个特定示例的范围。
猜你喜欢
  • 2014-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-15
  • 2011-05-29
  • 2018-06-15
相关资源
最近更新 更多