DataGridView internals

Costas

Administrator
Staff member
Have a CSV, 34570 rows with 169 columns...

this CSV read & added to a datatable and loaded to DataGridView through DataSource property

C#:
DataTable dt = General.ImportDelimitedFile(file4import, delimiter, col_headers);
dg.DataSource = dt;

or

C#:
DataTable dt = General.ImportDelimitedFile(file4import, delimiter, col_headers);
DataView f = dt.AsDataView();
dg.DataSource = f;

advantage = very quick load takes ~4 seconds (125mb in memory)
cons = very slow, on executing LINQ and when set visibility to rows

notes :
VS Error : Row associated with the currency manager's position cannot be made invisible
solution : dg.CurrentCell = null;


--

approach 1
add rows by hand :
C#:
List<DataGridViewRow> rows = new List<DataGridViewRow>(); //https://10tec.com/articles/why-datagridview-slow.aspx

while ((line = file.ReadLine()) != null)
{
    if (line.Trim().Length > 0)
    {
        line = line.Replace("\"", "");
  
        string[] cols = Regex.Split(line, delimiter, RegexOptions.Compiled);
        DataGridViewRow row = new DataGridViewRow();
        row.CreateCells(this, cols);
        rows.Add(row);
    }
}

this.Rows.AddRange(rows.ToArray());

tried any possible variant apart List<T>, all of them had the same result.

advantage = LINQ and visibility to rows extremely fast
cons = takes ~12 seconds. (700mb in memory, even call SetProcessWorkingSetSize)


C#:
//Hidding rows in the DataGridView is too slow
//src - https://social.msdn.microsoft.com/Forums/windows/en-US/68c8b93e-d273-4289-b2b0-0e9ea644623a
public class DataGridViewEx : DataGridView
{
    private bool m_Suspended = false;
    public bool Suspended
    {
        get { return m_Suspended; }
        set
        {
            if (m_Suspended != value)
            {
                m_Suspended = value;
                if (!m_Suspended && this.Rows.Count > 0)
                {
                    this.CurrentCell = null;
                    bool visible = this.Rows[0].Visible;
                    this.Rows[0].Visible = !visible;
                    this.Rows[0].Visible = visible;
                }
            }
        }
    }

    protected override void OnRowStateChanged(int rowIndex, DataGridViewRowStateChangedEventArgs e)
    {
        if (!m_Suspended) base.OnRowStateChanged(rowIndex, e);
    }

    public void BeginUpdate()
    {
        this.Suspended = true;
        DrawingControl.SuspendDrawing(this);
    }

    public void EndUpdate()
    {
        DrawingControl.ResumeDrawing(this);
        this.Suspended = false;
    }

    public void ClearGrid(){
        this.ClearSelection();
        this.CurrentCell = null;

        this.DataSource = null;
        this.Rows.Clear();
        this.Columns.Clear();
    }
}


//////////////

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

internal static class DrawingControl
{ //https://stackoverflow.com/a/16625788

    [DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);

    private const int WM_SETREDRAW = 11;

    /// <summary>
    /// Some controls, such as the DataGridView, do not allow setting the DoubleBuffered property.
    /// It is set as a protected property. This method is a work-around to allow setting it.
    /// Call this in the constructor just after InitializeComponent().
    /// </summary>
    /// <param name="control">The Control on which to set DoubleBuffered to true.</param>
    public static void SetDoubleBuffered(Control control)
    {
        // if not remote desktop session then enable double-buffering optimization
        if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
        {

            // set instance non-public property with name "DoubleBuffered" to true
            typeof(Control).InvokeMember("DoubleBuffered",
                                         System.Reflection.BindingFlags.SetProperty |
                                            System.Reflection.BindingFlags.Instance |
                                            System.Reflection.BindingFlags.NonPublic,
                                         null,
                                         control,
                                         new object[] { true });
        }
    }

    /// <summary>
    /// Suspend drawing updates for the specified control. After the control has been updated
    /// call DrawingControl.ResumeDrawing(Control control).
    /// </summary>
    /// <param name="control">The control to suspend draw updates on.</param>
    public static void SuspendDrawing(Control control)
    {
        SendMessage(control.Handle, WM_SETREDRAW, false, 0);
    }

    /// <summary>
    /// Resume drawing updates for the specified control.
    /// </summary>
    /// <param name="control">The control to resume draw updates on.</param>
    public static void ResumeDrawing(Control control)
    {
        SendMessage(control.Handle, WM_SETREDRAW, true, 0);
        control.Refresh();
    }
}



possible solution to use VirtualMode
Fast custom formulae, filtering and sorting in DataGrids
MS - Best Practices for Scaling the Windows Forms DataGridView Control
MS - Virtual Mode in the Windows Forms DataGridView Control
 
Top