首页 文章

为WinForms DataGridView行设置backcolor的最快方法

提问于
浏览
2

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

1 回答

  • 2

    要尝试的一件事是告诉窗口在循环更改时停止绘制控件 . 从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);
    

相关问题