Slow performance in populating DataGridView with large data

80,512

Solution 1

If you have a huge amount of rows, like 10,000 and more, to avoid performance leaks - do the following before data binding:

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

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

After the data is bound, you may re-enable it.

Solution 2

Make sure u don't auto-size columns, it improves performance.

i.e. don't do this:

Datagridview.Columns[I].AutoSizeMode = DataGridViewAutoSizeColumnMode.xxxxx;

Solution 3

Generally turning auto-sizing off and double buffering help to speed up DataGridView population. Check whether the DGV double buffering is turned on properly:

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

Disabling the redrawing with the WinAPI WM_SETREDRAW message also helps:

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

If you do not need 2-way data-binding or some features provided by BindingSource (filtering, etc.), you may consider adding rows at one go with the DataGridView.Rows.AddRange() method.

The link to the source article with the sample: http://10tec.com/articles/why-datagridview-slow.aspx

Solution 4

I know I'm late to the party, but I recently got fed up with how slow the auto resizing was for the the DataGridView control, and felt someone somewhere might benefit from my solution.

I created this extension method for manually measuring and resizing columns in a DataGridView. Set the AutoSizeColumnsMode to DataGridViewAutoSizeColumnsMode.None and call this method after setting the 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;
            }
        }
    }
}

While I certainly would never recommend populating a DGV with 1000+ rows, this method results in a huge performance benefit while producing very similar results to the AutoResizeColumns method.

For 10k Rows: (10K rows * 12 columns.)

AutoResizeColumns = ~3000 ms

FastAutoSizeColumns = ~140 ms

Solution 5

I had to disable auto-sizing in a few places to see the greatest improvement in performance. In my case, I had auto-size modes enabled for AutoSizeRowsMode, AutoSizeColumnsMode, and ColumnHeadersHeightSizeMode. So I had to disable each of these before binding the data to the DataGridView:

dataGridView.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;

// ... Bind the data here ...

// Set the DataGridView auto-size modes back to their original settings.
dataGridView.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
Share:
80,512
VJOY
Author by

VJOY

I am a Senior Software Developer. Working for a reputed software company. I like to learn new things in life, be it from any perspective. You can connect me at, [email protected] http://www.whatilearnttuday.blogspot.com/

Updated on August 30, 2021

Comments

  • VJOY
    VJOY almost 3 years

    I am using a BindingSource control (reference here) to populate my DataGridView control. There are around 1000+ records populating on it. I am using threading to do so. The DataGridView performs very slow in this case.

    I tried to set DoubleBuffered property to true, RowHeadersWidthSizeMode to disabled, AutoSizeColumnsMode to none. But still the same behavior.

    Please assist me in this. How can I improve the performance of the Grid.

    Thanks in advance,
    Vijay