简体   繁体   中英

c# very slow populating the datagridview

I'am populating a datagridview from a datatable.

While populating the columns and rows, I also format it at the same time, this cause the datagridview to load very slowly, is there a work around for this problem?

As well as taking care of AutoSizeColumnsMode , make sure that individual columns have their AutoSizeMode property also set to something other than all cells.

I also found it necessary to use

SendMessage(dg.Handle, WM_SETREDRAW, false, 0); // before

// updates to datagridview here...

SendMessage(dg.Handle, WM_SETREDRAW, true, 0); // after

With this will be datagridview fast as java jtable :)

public static class ExtensionMethods
{
    public static void DoubleBuffered(this DataGridView dgv, bool setting)
    {
        Type dgvType = dgv.GetType();
        PropertyInfo pi = dgvType.GetProperty("DoubleBuffered",
            BindingFlags.Instance | BindingFlags.NonPublic);
        pi.SetValue(dgv, setting, null);
    }
}

ExtensionMethods.DoubleBuffered(dataGridView1, true);

I was taking about 2-4 minutes to load 1-2k rows. I changed the auto-resize property and now it's down to seconds, probably 10-20. I ran this right before my row creation loop to ensure it got all the columns.

foreach (DataGridViewColumn c in thisGrid.Columns)
{
    c.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
}

You could check the property of DataGridView - AutoSizeColumnsMode I found that if I change the mode from AllCells to DisplayedCells the performance is different. I hope this will help you.

When you use a datagrid view to display data from dataabse you should always think to use some strategy to limit the results set and show records only when the user really see them. This is called sometime Virtual Mode, or data paging. I got an example of this strategy for wpf , but there is something also for winforms. Have a look at this question too: Winform DataGridview incredibly slow compared to MS Access Grid I think is related to your problem as well.

The rules of a stupid old chap : - AVOID the DataTable, well known to be inefficicient - AVOID using preallocation of rows ["Grid".Rowcount + "Grid".AddRange() +..] ( ~5 times slower than "Grid"ADD()) - Consider that a DataGridView is bound to "your screen" : ie. LOAD IT with a few screens of data. - I applied these simple facts and I can "load" a 'stupid file' of 420 000 rows with 159 columns in 15 sec. ( ~200 MB).

I have a fairly good performance of DataGridView . Adding several hundred rows takes about 200ms. Here's what I do:

virtual = true -- using a virtualized data grid view seems to make the whole process faster. Just remember to properly implement logViewGrid_CellValueNeeded .

Another thing to do is to temporarily disable layout events when adding data to bound list. Try to do:

logViewGrid.SuspendLayout();
// add data, perform some operations on grid view
logViewGrid.ResumeLayout(false);

I also had a problem with slow rows coloring ; my method for doing that was setting each cells' style separately, like this:

gridViewInstance.Rows[currentRow].Cells[cellIndex].Style.BackColor = val;

Instead, I went for:

gridViewInstance.Rows[currentRow].DefaultCellStyle.BackColor = val;

Which, for 30 columns, gave me significant speed increase in that part of the code.

I did some testing in a program where I load 5000 rows with 6 columns and each cell is loaded with the row number just to have some data. I then used Stopwatch to test each approach. I loaded the dataviewgrid, disabled it and loaded it then enabled it, hid it, loaded it, and showed it, and suspendlayout and resumelayout. I found that by hiding it and loading it and then showing it was much faster in my testing. It took: .91 seconds to just load .91 seconds to suspendLayout, load, resumeLayout .25 seconds to disable, load and reenable the grid .19 seconds to hide, load, and show the the grid.

I would agree that you should avoid loading what you dont need to, but thought this test would help.

我有同样的问题,在我的情况下,我还必须设置DataGridView.RowHeadersWidthSizeMode = DisableResizing

This is what I found worked. I was building a 52x15 grid with custom cell coloring and it was taking anywhere from 10-20 seconds to generate and display with all the suggestions above not improving performance much.

This change now makes it display in about 1 second along with the double-buffering above.

dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;

Then after it's done generating the data

dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;

For me the issue was with the ColumnHeadersHeightSizeMode property, so I suggest this code snippet that incorporates a number of suggestions from other respondents. This has the advantage of not blindly reverting to AutoSize if your grid was not AutoSized some way.:

private static void FastLoadDataGrid<T>(DataGridView dgv, IEnumerable<T> objList)
{
    // Cache old values
    DataGridViewAutoSizeColumnsMode oldAutoSizeCols = dgv.AutoSizeColumnsMode;
    DataGridViewAutoSizeRowsMode oldAutoSizeRows = dgv.AutoSizeRowsMode;
    DataGridViewRowHeadersWidthSizeMode oldRowHeader = dgv.RowHeadersWidthSizeMode;
    DataGridViewColumnHeadersHeightSizeMode oldCol = dgv.ColumnHeadersHeightSizeMode;

    dgv.SuspendLayout(); // off for performance 

    // switch off stuff for performance
    dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None; 
    dgv.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None; 
    dgv.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;
    dgv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;

    // flush and load data source 
    dgv.DataSource = null;
    dgv.DataSource = new List<T>(objList); //wrap in sortable bindinglist to allow user to sort via column header click

    // revert back to old values
    dgv.AutoSizeColumnsMode = oldAutoSizeCols;  
    dgv.AutoSizeRowsMode = oldAutoSizeRows; 
    dgv.RowHeadersWidthSizeMode = oldRowHeader;
    dgv.ColumnHeadersHeightSizeMode = oldCol;

    dgv.ResumeLayout(false); // turn back on
}

A typical call to this procedure is:

FastLoadDataGrid(MyDataGridView, MyListOfCustomers);

A test of importing 10000 rows with 3 columns and each success displayed in a data grid view went from eight seconds down to three seconds by using my FastLoadDataGrid.

Other suggestions from Microsoft are: DataGridView optimizations

A totally different approach that could done as well or instead of is to use virtualization. Turn on VirtualMode = true. But this potentially requires refactoring of the data bound events. See: DataGridView Virtualization

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM