2012-04-19 1 views
10

Sto utilizzando un controllo BindingSource per compilare il controllo datagridview. Ci sono circa 1000+ record che vi popolano. Sto usando il threading per farlo. In questo caso, il datagridview si comporta molto lentamente.Prestazioni lente nel popolamento di DatagridView con dati di grandi dimensioni

Ho provato a impostare la proprietà DoubleBuffered su true, RowHeadersWidthSizeMode su Disabled, AutoSizeColumnsMode su none. Ma ancora lo stesso comportamento.

Per favore aiutatemi. Come posso migliorare le prestazioni della griglia.

Grazie in anticipo,
Vijay

+0

pensano di paging/uso di filtri per i dati. – Reniuz

+0

Mi imbatto regolarmente nello stesso problema; Ho anche diversi 1000 record in una lista e devo usare il cercapersone per i record - che risolve il problema ma solleva nuovi problemi allo stesso tempo! – Argeman

+0

una delle domande più duplicate su SO – nawfal

risposta

14

Se si dispone di una quantità enorme di righe, come 10 000 e più,

da evitare perdite prestazioni - fare quanto segue prima l'associazione dati:

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; 

dopo che i dati binded si può abilitarlo.

+1

ho provato a inserire il codice nel mio file.Designer.vb e ho provato a eseguirlo correttamente. Come hai detto, imposta RowHeadersVisible su False e poi ... dopo Binding, rendi RowHeadersVisible nuovamente su True. Questa è una buona soluzione e funziona! Ma sfortunatamente, se ho apportato alcune modifiche alla GUI (Front), il codice che inserisco nel file.Designer.vb viene nuovamente riportato al rendering predefinito da Visual Studio. Come posso gestire questo? @okarpov? – gumuruh

+0

@gumuruh inserisce il codice di disabilitazione nel costruttore di classe e inserisce il codice di attivazione da qualche parte dopo il binding – okarpov

+0

Problemi di ContentSwitchDeadlock durante il caricamento di grandi quantità (100.000+) righe in un datagridview. Passare da 'autoSizeAllHeaders' a' EnableResizing' ha funzionato! Grazie. – kaycee

0

Penso che è necessario considerare l'utilizzo di griglia di dati in virtual mode. In pratica, si impostano le estensioni della griglia in primo piano, quindi si esegue l'override di "OnCellValueNeeded" come richiesto.

Si dovrebbe trovare (in particolare per solo 1000 o più righe) che la popolazione della griglia diventi effettivamente istantanea.

Buona fortuna,

3

Se non si desidera ignorare la modalità virtuale metodi richiesti di DataGridView c'è un'altra alternativa se si potrebbe considerare l'utilizzo di ListView:

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

  • Ha una versione (FastObjectListView) che può creare un elenco di 100.000 oggetti in meno di 0,1 secondi.
  • Ha una versione (DataListView) che supporta l'associazione dati e un altro (FastDataListView) che supporta l'associazione dati su set di dati di grandi dimensioni (100.000+).
5

assicurarsi u non autosize colonne, migliora le prestazioni.

, ad esempio non fare questo Datagridview.Columns [I] .AutoSizeMode = DataGridViewAutoSizeColumnMode.xxxxx;

+1

O quello che ho appena fatto - disattivare il dimensionamento automatico mentre si popola la griglia, quindi riaccenderla. Avevo circa 15.000 voci in totale, direi che l'accelerazione è stata di almeno 100x, probabilmente molto di più. –

5

Generalmente disattivazione del ridimensionamento automatico e doppio buffering per velocizzare la popolazione di DataGridView. Controllare se il doppio buffering DGV è attivato correttamente:

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

La disattivazione del ridisegno con l'WinAPI WM_SETREDRAW messaggio aiuta anche:

// *** 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(); 

Se non hanno bisogno di 2 vie di associazione dati o alcune funzioni fornito da BindingSource (filtraggio, ecc.), puoi prendere in considerazione l'aggiunta di righe in una volta sola con il metodo DataGridView.Rows.AddRange().

Il link per l'articolo di origine con il campione: http://10tec.com/articles/why-datagridview-slow.aspx

1

So di essere in ritardo alla festa, ma di recente ho stufo con la lentezza il ridimensionamento automatico è stato per il controllo DataGridView, e mi sentii qualcuno da qualche parte potrebbe beneficiare della mia soluzione.

Ho creato questo metodo di estensione per misurare e ridimensionare manualmente le colonne in un DataGridView. Impostare AutoSizeColumnsMode su DataGridViewAutoSizeColumnsMode.None e chiamare questo metodo dopo aver impostato il DataSource.

/// <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; 
      } 
     } 
    } 
} 

Mentre io certamente consiglierei mai compilazione di un DGV con 1000+ file, questo metodo si traduce in un enorme vantaggio delle prestazioni, mentre la produzione risultati molto simili alle AutoResizeColumns metodo.

Per 10k Righe: (. 10K righe * 12 colonne)

AutoResizeColumns = ~ 3000 ms

FastAutoSizeColumns = ~ 140 ms