I have a Form in my application that displays some data. When I first show the Form, I load some data into a DataTable then bind the DataTable to a DataGridView. I also start an asynchronous method that executes some slower database queries. When these slow queries complete, I need to update a few hundred rows in the DataTable, filling in values returned from the slower queries, like so:
foreach (DataRow row in data.Rows)
{
SlowLoadingData slow_stuff = slow_query_results[(int)row["id"]];
row.BeginEdit();
row[column_one] = slow_stuff.One;
row[column_two] = slow_stuff.Two;
row[column_three] = slow_stuff.Three;
row.EndEdit();
}
This is extremely slow, hanging the UI thread for a minute or more, presumably because each row is triggering a redraw.
After some research, I found a way to make it fast. First, bind the DataGridView to a BindingSource that is bound to the DataTable, instead of directly to the DataTable. Then, do as follows when you make changes to the DataTable:
binding_source.SuspendBinding();
binding_source.RaiseListChangedEvents = false;
// foreach (DataRow in Data.Rows) ... code above
binding_source.RaiseListChangedEvents = true;
binding_source.ResumeBinding();
grid.Refresh();
There is a problem, though, and it's a doozy: the code above prevents the DataGridView from detecting new rows added to the DataTable. Any new rows added to the table do not appear in the grid. The grid may also throw exceptions if you use the arrow keys to move the current cell selection off the bottom end of the grid, because the underlying data source has more rows but the grid has not created grid rows to display them.
So, two possible solutions that I can see:
Is there a better way to suppress binding updates while making changes to the underlying DataTable?
Is there an easy way to tell the DataGridView to gracefully refresh its grid row collection to match the number of underlying DataTable rows? (Note: I've tried calling BindingSource.ResetBindings, but it seems to trigger more exceptions if you have removed rows from the DataTable!)