我有一个绑定到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,或者我看到的速度只是我正在使用的数据大小的问题?
答案 0 :(得分: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);