web-dev-qa-db-fra.com

Ralentissement des performances en remplissant DatagridView avec des données volumineuses

J'utilise un contrôle BindingSource pour remplir le contrôle datagridview. Il y a plus de 1000 enregistrements qui y figurent. J'utilise le filetage pour le faire. La datagridview fonctionne très lentement dans ce cas.

J'ai essayé de définir la propriété DoubleBuffered sur true, RowHeadersWidthSizeMode sur désactivé, AutoSizeColumnsMode sur aucun. Mais toujours le même comportement.

S'il vous plaît aidez-moi dans ce Comment puis-je améliorer les performances de la grille?.

Merci d'avance,
Vijay

14
Vijay Balkawade

Si vous avez une quantité énorme de lignes, comme 10 000 et plus,

pour éviter toute perte de performances, procédez comme suit avant de lier les données:

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;

une fois les données liées, vous pouvez l'activer.

20
okarpov

assurez-vous de ne pas redimensionner automatiquement les colonnes, cela améliore les performances.

c'est-à-dire ne faites pas cela Datagridview.Columns [I] .AutoSizeMode = DataGridViewAutoSizeColumnMode.xxxxx;

11
saumil patel

En général, désactiver la mise en taille automatique et la double mise en mémoire tampon aide à accélérer le remplissage de DataGridView. Vérifiez si le double tampon DGV est activé correctement:

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

Désactiver la mise à jour avec WinAPI WM_SETREDRAW message aide également à:

// *** 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 vous n'avez pas besoin de liaison de données bidirectionnelle ou de certaines fonctionnalités fournies par BindingSource (filtrage, etc.), vous pouvez envisager d'ajouter des lignes en une fois avec la méthode DataGridView.Rows.AddRange () .

Le lien vers l'article source avec l'exemple: http://10tec.com/articles/why-datagridview-slow.aspx

7
TecMan

Si vous ne souhaitez pas remplacer les méthodes requises du mode virtuel par DataGridView, il existe une autre alternative si vous pouvez envisager d'utiliser Listview:

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

  • Il possède une version (FastObjectListView) pouvant générer une liste de 100 000 objets en moins de 0,1 seconde. 
  • Il a une version (DataListView) qui supporte la liaison de données, et un autre (FastDataListView) qui prend en charge la liaison de données sur de grands ensembles de données (plus de 100 000).
3
HischT

Je sais que je suis en retard à la fête, mais j'en ai récemment marre de la lenteur du redimensionnement automatique du contrôle DataGridView et je me suis dit que quelqu'un, quelque part, pourrait bénéficier de ma solution.

J'ai créé cette méthode d'extension pour mesurer et redimensionner manuellement les colonnes dans un DataGridView. Définissez AutoSizeColumnsMode sur DataGridViewAutoSizeColumnsMode.None et appelez cette méthode après avoir défini le 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;
            }
        }
    }
}

Bien que je ne recommande certainement jamais de renseigner un DGV avec plus de 1 000 lignes, cette méthode offre un avantage considérable en termes de performances tout en produisant des résultats très similaires à ceux de la méthode AutoResizeColumns

Pour 10k lignes: (10K lignes * 12 colonnes.)

AutoResizeColumns = ~ 3000 ms

FastAutoSizeColumns = ~ 140 ms

3
Bobby L

J'ai eu un problème de performance lorsque l'utilisateur a chargé 10 000 éléments ou les a triés .

this.dataEvents.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.AllCells;

Tout est devenu bien.

2
Serov Danil

Je pense que vous devez envisager d’utiliser votre grille de données en mode virtuel . Fondamentalement, vous définissez les étendues de la grille en amont, puis substituez "OnCellValueNeeded" selon les besoins.

Vous devriez trouver (en particulier pour seulement 1000 lignes environ) que votre population de grille devient effectivement instantanée.

Bonne chance,

0
Adrian Conlon