2012-04-19 15 views
10

Estoy utilizando un control BindingSource para llenar el control de datagridview. Hay alrededor de más de 1000 registros poblando en él. Estoy usando threading para hacerlo. El datagridview funciona muy lento en este caso.Rendimiento lento al rellenar DatagridView con datos grandes

Intenté establecer la propiedad DoubleBuffered en true, RowHeadersWidthSizeMode en disabled, AutoSizeColumnsMode en none. Pero sigue siendo el mismo comportamiento.

Por favor, ayúdenme en esto. ¿Cómo puedo mejorar el rendimiento de la Grilla?

Gracias de antemano,
Vijay

+0

piensan de paginación/el uso de filtros para los datos. – Reniuz

+0

Normalmente me encuentro con el mismo problema; También tengo varios miles de registros en una lista y tengo que usar paginación para los registros, lo que resuelve el problema pero plantea nuevos problemas al mismo tiempo. – Argeman

+0

una de las preguntas más duplicada en SO – nawfal

Respuesta

14

Si usted tiene una gran cantidad de filas, al igual que 10 000 y más,

para evitar la fuga de rendimiento - hacer lo siguiente antes de enlace de datos:

dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing; //or even better .DisableResizing. Most time consumption enum is DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders 

// set it to false if not needed 
dataGridView1.RowHeadersVisible = false; 

después de los datos binded que pueden activarlo.

+1

intenté poner tu código dentro de mi archivo.Designer.vb y traté de ejecutarlo correctamente. Como dijo, establezca RowHeadersVisible en False y luego ... después de Enlace, haga que RowHeadersVisible vuelva a True. ¡Esa es una buena solución y funciona! Pero, por desgracia, si realicé algunos cambios en la GUI (Delante), el código que puse dentro de file.Designer.vb vuelve a ser el predeterminado procesado por Visual Studio. ¿Cómo puedo manejar esto? @okarpov? – gumuruh

+0

@gumuruh poner el código de desactivación en su contra el constructor de la clase y poner permitiendo código en algún lugar después de la unión – okarpov

+0

he estado teniendo problemas ContentSwitchDeadlock al cargar grandes cantidades (100 000+) filas de un DataGridView. Cambiar de 'autoSizeAllHeaders' a' EnableResizing' hizo el trabajo! Gracias. – kaycee

0

creo que es necesario considerar el uso de la cuadrícula de datos en virtual mode. Básicamente, establece las extensiones de la grilla por adelantado y luego anula "OnCellValueNeeded" según sea necesario.

Debería encontrar (especialmente para solo 1000 filas o más) que su población de cuadrícula se convierta en realidad instantánea.

Buena suerte,

3

Si no desea anular el modo virtual métodos necesarios de DataGridView hay otra alternativa si usted podría considerar el uso de Listview:

http://www.codeproject.com/Articles/16009/A-Much-Easier-to-Use-ListView

  • Tiene una versión (FastObjectListView) que puede generar una lista de 100.000 objetos en menos de 0.1 segundos.
  • Tiene una versión (DataListView) que admite el enlace de datos, y otra (FastDataListView) que admite el enlace de datos en grandes conjuntos de datos (100.000+).
5

asegúrese de que u no de tamaño automático columnas, que mejora el rendimiento.

es decir, no haga esto Datagridview.Columns [I] .AutoSizeMode = DataGridViewAutoSizeColumnMode.xxxxx;

+1

O lo que acaba de hacer - apagar el tamaño automático al rellenar la grilla, luego vuelva a encenderla. Tenía unas 15,000 entradas en total, diría que la aceleración fue de al menos 100x, probablemente mucho más. –

5

En general, desactivar el autodimensionamiento y el doble almacenamiento en memoria intermedia ayuda a acelerar la población de DataGridView. Compruebe si el búfer doble DG V se enciende correctamente:

if (!System.Windows.Forms.SystemInformation.TerminalServerSession) 
{ 
    Type dgvType = dataGridView1.GetType(); 
    PropertyInfo pi = dgvType.GetProperty("DoubleBuffered", 
    BindingFlags.Instance | BindingFlags.NonPublic); 
    pi.SetValue(dataGridView1, value, null); 
} 

Deshabilitar el nuevo trazado con la API de Windows WM_SETREDRAW mensaje también ayuda a:

// *** API Declarations *** 
[DllImport("user32.dll")] 
private static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam); 
private const int WM_SETREDRAW = 11; 

// *** DataGridView population *** 
SendMessage(dataGridView1.Handle, WM_SETREDRAW, false, 0); 
// Add rows to DGV here 
SendMessage(dataGridView1.Handle, WM_SETREDRAW, true, 0); 
dataGridView1.Refresh(); 

Si no necesitan de 2 vías de enlace de datos o algunas de las características proporcionado por BindingSource (filtrado, etc.), puede considerar agregar filas de una vez con el método DataGridView.Rows.AddRange().

El enlace al artículo fuente con la muestra: http://10tec.com/articles/why-datagridview-slow.aspx

1

Sé que llego tarde a la fiesta, pero recientemente harté de lo lento que el cambio de tamaño automático era para el control DataGridView, y me sentí alguien en algún lugar podría beneficiarse de mi solución.

he creado este método de extensión para medir y cambiar el tamaño de las columnas en un DataGridView manualmente. Ajuste el AutoSizeColumnsMode a DataGridViewAutoSizeColumnsMode.None y llamar a este método después de establecer el origen de datos.

/// <summary> 
/// Provides very fast and basic column sizing for large data sets. 
/// </summary> 
public static void FastAutoSizeColumns(this DataGridView targetGrid) 
{ 
    // Cast out a DataTable from the target grid datasource. 
    // We need to iterate through all the data in the grid and a DataTable supports enumeration. 
    var gridTable = (DataTable)targetGrid.DataSource; 

    // Create a graphics object from the target grid. Used for measuring text size. 
    using (var gfx = targetGrid.CreateGraphics()) 
    { 
     // Iterate through the columns. 
     for (int i = 0; i < gridTable.Columns.Count; i++) 
     { 
      // Leverage Linq enumerator to rapidly collect all the rows into a string array, making sure to exclude null values. 
      string[] colStringCollection = gridTable.AsEnumerable().Where(r => r.Field<object>(i) != null).Select(r => r.Field<object>(i).ToString()).ToArray(); 

      // Sort the string array by string lengths. 
      colStringCollection = colStringCollection.OrderBy((x) => x.Length).ToArray(); 

      // Get the last and longest string in the array. 
      string longestColString = colStringCollection.Last(); 

      // Use the graphics object to measure the string size. 
      var colWidth = gfx.MeasureString(longestColString, targetGrid.Font); 

      // If the calculated width is larger than the column header width, set the new column width. 
      if (colWidth.Width > targetGrid.Columns[i].HeaderCell.Size.Width) 
      { 
       targetGrid.Columns[i].Width = (int)colWidth.Width; 
      } 
      else // Otherwise, set the column width to the header width. 
      { 
       targetGrid.Columns[i].Width = targetGrid.Columns[i].HeaderCell.Size.Width; 
      } 
     } 
    } 
} 

Mientras que sin duda nunca recomendaría llenar una DGV con 1000 filas, este método da como resultado una gran mejora en el rendimiento mientras que produce resultados muy similares a los AutoResizeColumns método.

Para 10k Filas: (. 10K filas * 12 columnas)

AutoResizeColumns = ~ 3000 ms

FastAutoSizeColumns = ~ 140 ms

Cuestiones relacionadas