3

I know there are several questions in SO about slow DataGridViews, but I tried really everything mentioned there and most are about more complex databinding.

what I did before:

  • I tested DataTable as Datasource
  • unbound Datagridview, populated in a loop
  • tested many setting with autoColumnResizing etc. all tests are too slow.

This example is only a datgridview in a main form, plain stock from Designer's Toolbox, edit off. enter image description here

Even if it's only 100 lines it feels very laggy when scrolling and redrawing and it's maxing out one core.

I did a VS profiler session when scrolling in the datagridview:

enter image description here

I'd like to dig deeper and understand what exactly makes this control so slow and what can be done to accelerate it or what alternatives I can use to get a fast table which is able to be sorted by clicking the column headers.

public partial class Form1 : Form
{
   List<Record> myData;
    public Form1()
    {
        InitializeComponent();
        myData = getListofRecord();

        dataGridView1.DataSource = myData;
    }

    private static List<Record> getListofRecord()
    {
        var myTable = new List<Record>();
        for (int i = 0; i < 500; i++)
        {
            myTable.Add(new Record() { a = 121+i, b = 123.2434F, c = 2342, d = 312+i*2, e = 123343, f = 12323 });
        }
        return myTable;
    }

}

public class Record
{
    public Single a { get; set; }
    public Single b { get; set; }
    public Single c { get; set; }
    public Single d { get; set; }
    public Single e { get; set; }
    public Single f { get; set; }

}

Edit:

2 days later I get a different result when rerunning the test app on the same machine. It's quite as fast as I would expect and the profiling may lead to the reason? in the hotpath stack the CreateSemiCompatibleDIB is missing.

enter image description here

Edit2:

whatever the true reason behind the 1st difference is, turning on double buffering by reflection did the most obvious and roughly 20x faster effect. I have seen these suggestion in other DGV questions but was only expecting to get a slight visual improvement, not a complete new experience.

the profiling hotpath now shows a completely different call stack.

enter image description here

Edit3

to save my profiling work in this question and not being deleted as duplicate I would like to get some objective numbers in milliseconds for a redraw of the DGV. Where do I need to place a stopwatch to get these?

Community
  • 1
  • 1
Falco Alexander
  • 3,092
  • 2
  • 20
  • 39
  • Does the (re)draw code involve calling that `getListofRecord` method? There is no need to move data into a DataTable; use a BindingList and you can add/remove data from the collection and it will instantly flow thru. The code posted doesnt show it, but I will guess that you "refresh" the datasaiurce by setting it to null then back to the new datatable? – Ňɏssa Pøngjǣrdenlarp Jan 06 '18 at 17:13
  • @Plutonix there is no explicit redraw code. only these lines of code I inserted in the Q. It behaves the same when I bind it to a static object. Data to be shown is read only and won't change after inital read. I edited the code slightly to make that clear. – Falco Alexander Jan 06 '18 at 17:17
  • In that case, please define "(re)draw". If there data doesnt change, when the form repaints (from say another window covering it up or Restoring from Minimixzed), only the number of rows shown get repainted; the total number doesnt matter. Sorting will act on all the data but even then, only the rows showing are repainted. It is hard to solve for "feels laggy"; too subjective. – Ňɏssa Pøngjǣrdenlarp Jan 06 '18 at 17:24
  • 1
    when I use the scrollbars it feels laggy. like it redraws the 13x5 visible cells in 300ms which is badly slow. To give it some real comparable numbers you are welcome to help with ideas how to measure it completely objectively :) may be a screenshot of the tiny app+datagrid helps? – Falco Alexander Jan 06 '18 at 19:16
  • 1
    Make the DGV [DoubleBuffered](https://stackoverflow.com/questions/44185298/update-datagridview-very-frequently/44188565?s=2|51.1534#44188565)! – TaW Jan 07 '18 at 09:56
  • @TaW that was the trick. please see the edits in my Q – Falco Alexander Jan 09 '18 at 13:11
  • @TaW any idea what causes the difference from the original profiling result to the one in the first edit (w/o dbl buf)? – Falco Alexander Jan 09 '18 at 13:21
  • No, sorry but I can't dig into this. I'm on the community edition only, so I don't think I even could do any profiling. - Btw: I can re-open the question if you want to – TaW Jan 09 '18 at 13:41
  • @TaW Community edition has all the profiling features you need (Alt+F2). re-opening would be nice – Falco Alexander Jan 09 '18 at 14:32

2 Answers2

3

simple as that and thanks to TaW:

using System.Reflection;

static void SetDoubleBuffer(Control dgv, bool DoubleBuffered)
{
    typeof(Control).InvokeMember("DoubleBuffered", 
        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, 
        null, dgv, new object[] { DoubleBuffered });
}

and VB.NET:

 Public Sub DoubleBuffered(ByVal dgv As DataGridView, ByVal setting As Boolean)
      Dim dgvType As Type = dgv.[GetType]()
      Dim pi As PropertyInfo = dgvType.GetProperty("DoubleBuffered", BindingFlags.Instance Or BindingFlags.NonPublic)
      pi.SetValue(dgv, setting, Nothing)
   End Sub
Falco Alexander
  • 3,092
  • 2
  • 20
  • 39
2

I am writing this as answer if anyone like me couldn't find a proper solution even did all of the suggested things. I had same problem and also tried all of the suggested things but noone worked even DoubleBuffered. Then I realized it is because of that I am handling DataGridView1.CellPainting event. If anyone struggling like me it is probably because of a handled DataGridView event, especially Cell events are slowing DataGridView extremely. So, I suggest that try to get rid of these handled events. Just this approach worked for me.

Celuk
  • 561
  • 7
  • 17