Reputation: 7240
I have a WinForms DataGridView that is bound to a BindingSource which, in turn, is bound to a BindingList of 100,000 objects.
BindingList<MyObject> myObjectList = new BindingList<MyObject>();
BindingSource bindingSourceForMyObjects = new BindingSource();
bindingSourceForMyObjects.DataSource = myObjectList;
dataGridViewMyObjects.DataSource = bindingSourceForMyObjects;
I have an event handler hooked up to my DataGridView's CellValueChanged event that contains the following code:
dataGridViewMyObjects.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red;
dataGridViewMyObjects.Rows[e.RowIndex].DefaultCellStyle.ForeColor = Color.White;
So when my user changes a row, this event handler fires and changes the row to white on red to indicate that the data has changed. This works great but I also have some cases where I need to programatically change the underlying list and I'd like those changes to reflect in the DataGridView, as well. To accomplish that, my object class implements INotifyPropertyChanged and I have an event handler hooked up to the ListChanged event of my BindingSource. The code in that event handler looks like this:
if (e.ListChangedType == ListChangedType.ItemChanged)
{
dataGridViewMyObjects.Rows[e.NewIndex].DefaultCellStyle.BackColor = Color.Red;
dataGridViewMyObjects.Rows[e.NewIndex].DefaultCellStyle.ForeColor = Color.White;
}
This is also working so if I programatically modify 50 of the objects, the DataGridView rows get updated as well. However, as I said before, I have 100,000 objects that I'm dealing with and if I need to modify more than ~800 objects, it can take a while because of all the calls to OnPropertyChanged() in my object. In the absolute worst case, if I need to modify all 100,000 objects, it can take nearly 1 minute for this to happen.
Inside of my object class, I have a boolean variable which I use to avoid triggering the OnPropertyChanged() call when I'm programatically doing "bulk" updates (> 800 objects). This makes updating the object properties very fast but the corresponding rows in the DataGridView don't get their forecolor/backcolor values updated anymore since the two-way binding is being bypassed. I know which rows correspond to the objects that were modified and I've tried looping through them and updating the ForeColor/BackColor values but again, it takes nearly a minute for this operation to complete.
I've tried wrapping that loop in...
dataGridViewMyObjects.SuspendLayout();
// loop here
dataGridViewMyObjects.ResumeLayout();
but that didn't seem to make a difference in performance. Is there a faster way to set the ForeColor/BackColor for lots of rows or is the speed I'm seeing simply a matter of the size of the data that I'm working with?
Upvotes: 2
Views: 1475
Reputation: 81620
One thing to try is to tell windows to stop painting your control while you loop through your changes. From 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();
}
}
Then your code would look like this:
DrawingControl.SuspendDrawing(dataGridViewMyObjects);
// loop here
DrawingControl.ResumeDrawing(dataGridViewMyObjects);
Upvotes: 3