Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

High-Performance WinForms DataGridView with Virtual Mode

Tech May 14 2

Loading tens of thousands of records into a DataGridView at once quickly becomes a bottleenck: the control allocates every row and cell object up-front, memory pressure rises, and the UI freezes. Virtual mode solves this by keeping the data in a separate collection and asking the grid for only the rows that are actually visible.

Preparing the data source

Use a BindingList<T> so the grid can be notified of inserts/removes without extra plumbing.

private readonly BindingList<Document> _cache = new BindingList<Document>();

Enabling virtual mode

Flip the switch in the designer or code:

grid.VirtualMode = true;

Virtual mode disables double-buffering by default, so turn it on via reflection to avoid flicker:

public static void EnableDoubleBuffer(Control c, bool on = true)
{
    var prop = typeof(Control).GetProperty("DoubleBuffered",
        BindingFlags.Instance | BindingFlags.NonPublic);
    prop?.SetValue(c, on);
}

// in Form_Load
EnableDoubleBuffer(grid);

Keeping counts in sync

Whenever the underlying list changes, update the grid’s RowCount and invalidate the visible area. The helper below marshals to the UI thread if necessary.

private void WireEvents()
{
    _cache.ListChanged += (s, e) =>
    {
        this.InvokeIfRequired(() =>
        {
            grid.RowCount = _cache.Count;
            grid.Invalidate();
        });
    };
}

Adding or removing items

All mutations go through the list; the grid never touches the data directly.

lock (_syncRoot)
{
    _cache.Add(new Document { Name = "New file", Status = Status.Pending });
}

Supplying cell values on demand

Handle CellValueNeeded. The grid calls this once for every visible cell, passing row and column indices.

private void grid_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
    if (_cache == null || e.RowIndex >= _cache.Count) return;

    var doc = _cache[e.RowIndex];

    switch (e.ColumnIndex)
    {
        case 0:  // icon
            e.Value = IconIndex.Normal;
            break;

        case 1:  // row number
            e.Value = e.RowIndex + 1;
            break;

        case 2:  // status text
            e.Value = doc.State == 0
                ? doc.StateRemark
                : EnumHelper.GetDisplayName(doc.ExceptionType);
            break;

        case 3:  // upload flag
            e.Value = doc.IsUploaded && doc.IsCloudSynced ? "Uploaded" : "Pending";
            break;

        case 4:  // file name
            e.Value = doc.Name;
            break;

        case 5:  // serial number
            e.Value = doc.Meta?.Serial ?? "-";
            break;

        default: // dynamic columns
            int dataIndex = e.ColumnIndex - 6;
            if (doc.Answers != null && dataIndex < doc.Answers.Count)
                e.Value = string.IsNullOrWhiteSpace(doc.Answers[dataIndex].Content)
                    ? "-"
                    : doc.Answers[dataIndex].Content;
            else
                e.Value = "-";
            break;
    }
}

Because the grid is in virtual mode, you never touch Rows or Cells collections; all interaction is routed through CellValueNeeded. The result is a responsive UI that can comfortably handle hundreds of thousadns of rows with minimal memory footprint.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.