Cargando DataTable lento cuando está enlazado a DataGridView.Datasource

He buscado por todas partes y no puedo entender esto. Estoy trabajando en una interfaz de usuario de Winforms que extrae grandes volúmenes de filas que necesito mostrar en un DataGridView. Ya he leído todo acerca de cómo limitar los recuentos de filas y la paginación y no hay absolutamente ninguna buena manera de hacerlo. Básicamente, estoy trabajando en el control TargetDataViewer del Extended Events Manager para SQL Server 2008 que escribí en Codeplex.

http://extendedeventmanager.codeplex.com/

Estoy limitado a lo que puedo hacer según el objective específico y la forma en que presenta los datos. Lo que estoy tratando de hacer es transmitir los datos que han sido leídos desde un objective a DataGridView de manera similar a como Profiler o SQL Server Management Studio muestran los datos a medida que se transmiten. Reescribí una gran cantidad de código y tengo un BackgroundWorker que extrae datos. y procesándolo en un DataTable. Si no configuro DataGridView.DataSource = DataTable, puedo cargar más de 300K filas de datos en DataTable en unos minutos, realmente se ejecuta rápidamente. Tan pronto como agrego el DataTable al DataSource, este se ralentiza casi hasta detenerse (en lugar de unos minutos, las mismas filas de 300K pueden demorar 1/2 hora).

Sé que el problema no es mi código de procesamiento, es específico para estar vinculado a DataGridView.DataSource, y tengo un código de tiempo para demostrarlo. No puedo averiguar cómo solucionar esto. Para el rendimiento, puedo vincular el control a DataTable después de que se carguen los datos, pero esa es una experiencia de usuario realmente horrible. Veo a mucha gente quejándose del impacto en el rendimiento de DataGridView al cargar datos, así que esto puede ser una limitación con la que me quedo. ¿Algunas ideas?

Piense en lo que sucede cuando rellena una DataTable con una fila de un DataReader : se crea un DataRow , se rellena desde el DataReader y se agrega a la colección Rows . Luego, cuando crea el enlace, DataGridView extrae datos de la tabla y crea la vista en la pantalla.

¿Qué sucede cuando se rellena un DataTable cuyo enlace a DataGridView está habilitado? Todo un lío de manejo de eventos. Cada vez que cambia una propiedad enlazada, el evento modificado por la propiedad se genera y el control enlazado lo maneja. Eso no está sucediendo 300,000 veces, está ocurriendo 300,000 veces para cada columna .

¿Qué pasa si desactivas esto y solo actualizas el control de límite ocasionalmente? Mira este método:

 private void PopulateDataTable() { int rowCount = 10000; bindingSource1.RaiseListChangedEvents = false; for (int i = 0; i < rowCount; i++) { DataRow r = DT.NewRow(); for (int j = 0; j < ColumnCount; j++) { r[j] = "Column" + (j + 1); } DT.Rows.Add(r); if (i % 500 == 0) { bindingSource1.RaiseListChangedEvents = true; bindingSource1.ResetBindings(false); Application.DoEvents(); bindingSource1.RaiseListChangedEvents = false; } } bindingSource1.RaiseListChangedEvents = true } 

Debe llamar a ResetBindings para forzar la actualización del control enlazado. Esto lleva tiempo, porque no puede evitar el costo de construir los objetos DataGridViewRow , pero eliminar los eventos es una mejora significativa. En mi máquina, si relleno un DataTable 10 columnas y 10000 filas que está vinculado a un DataGridView , toma 2900 milisegundos. Si dejo el enlace de datos desactivado todo el tiempo, tomará 155 milisegundos. Si reinicio los enlaces cada 500 filas, tomará 840 milisegundos.

Por supuesto, si estuviera rellenando la tabla de 300,000 filas, no restablecería los enlaces cada 500 filas; Probablemente lo haga una vez en la marca de las 500 filas y luego lo apague hasta que finalice la operación. Pero incluso si haces esto, debes llamar a Application.DoEvents vez en cuando, para que la interfaz de usuario pueda responder a los eventos.

Editar

No importa eso poco sobre Application.DoEvents ; no necesita hacer eso si está rellenando la tabla en una tarea en segundo plano.

Pero debe asegurarse de restablecer los enlaces en el controlador de eventos ProgressChanged BackgroundWorker , y no en el método DoWork . Y experimentará una gran cantidad de daño si realmente le permite al usuario editar los datos en el DataGridView vinculado mientras está llenando su fuente de datos en otro hilo.