为什么DataGridView(重新)绘制如此之慢?

时间:2018-01-06 17:10:05

标签: c# winforms performance datagridview

我知道关于缓慢的DataGridViews有几个问题,但我尝试了那里提到的所有内容,而且大多数是关于更复杂的数据绑定。

我之前做过的事情:

  • 我测试了DataTable作为Datasource
  • 未绑定的Datagridview,填充在循环中
  • 使用autoColumnResizing等测试了许多设置。 所有测试都太慢了。

此示例仅是主窗体中的datgridview,来自Designer工具箱的普通股,编辑关闭。 enter image description here

即使它只有100行,在滚动和重绘时感觉非常迟钝,而且它最大化了一个核心。

在datagridview中滚动时我做了一个VS profiler会话:

enter image description here

我想更深入地了解究竟是什么让这种控制变得如此缓慢以及可以采取哪些措施来加速它或者我可以使用哪些替代方法来获得快速表格,可以通过单击列来对其进行排序头。

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; }

}

编辑:

2天后,我在同一台机器上重新运行测试应用程序时得到了不同的结果。 它的速度和我预期的一样快,分析可能会导致原因吗? 在热路径堆栈中,CreateSemiCompatibleDIB丢失了。

enter image description here

EDIT2:

无论第一个差异背后的真正原因是什么,通过反射打开双缓冲效果最明显,效果大约快20倍。 我在其他DGV问题中看到了这些建议,但只是期望获得轻微的视觉改善,而不是全新的体验。

profiling hotpath现在显示一个完全不同的调用堆栈。

enter image description here

EDIT3

保存我在这个问题中的分析工作,而不是作为重复删除我希望得到一些客观数字,以毫秒为单位重绘DGV。 我需要在哪里放一个秒表来获取这些?

2 个答案:

答案 0 :(得分:1)

如果像我这样的人即使做了所有建议的事情也找不到合适的解决方案,我会写这个作为答案。 我遇到了同样的问题,也尝试了所有建议的事情,但没有人工作,甚至 session_start(); var_dump($_SESSION); //NULL echo "ss->".session_id(); //ss-> 。然后我意识到这是因为我正在处理 DoubleBuffered 事件。如果有人像我一样挣扎,那可能是因为处理了 DataGridView 事件,尤其是 Cell 事件正在极大地减慢 DataGridView。所以,我建议尝试摆脱这些处理过的事件。正是这种方法对我有用。

答案 1 :(得分:0)

就这么简单,感谢TaW:

using System.Reflection;

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

和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