为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

Posted

技术标签:

【中文标题】为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?【英文标题】:Why does the DoubleBuffered property default to false on a DataGridView and why is it protected?为什么 DataGridView 上的 DoubleBuffered 属性默认为 false,为什么它受到保护? 【发布时间】:2010-09-20 03:25:22 【问题描述】:

我们遇到了 DataGridViews 的性能问题,重绘速度非常慢,我们找到了解决方案 Here 来创建派生类型并在控件上启用双缓冲。 (派生类型是必需的,因为 DoubleBuffered 属性是受保护的)

将 DoubleBuffered 属性设置为 true 似乎没有任何缺点。

【问题讨论】:

【参考方案1】:

我认为它的最佳解决方案:

typeof(DataGridView).InvokeMember(
   "DoubleBuffered", 
   BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
   null, 
   myDataGridViewObject, 
   new object[]  true );

找到here

【讨论】:

问题是问为什么它被设置为false,而不是如何覆盖它。 虽然对寻找如何启用双缓冲区的人有所帮助。【参考方案2】:

它受到保护是因为 DGV 继承了 Control 的属性。并且 Control.DoubleBuffered 受到保护。这是有道理的,因为每个派生控件都应该自己决定打开它。而且控制用户随意开启或关闭也没有任何意义。 DGV 设计师决定离开。

他们可能决定这样做的一个原因是双缓冲实际上会使绘制速度变慢。渲染缓冲区位图的额外步骤需要时间。它只是在人眼看来更快,您会观察到突然出现的位图。您看不到绘制位图所需的时间。除非需要绘制其他控件并且在 DGV 之后轮到它们,否则它是相当可见的。

您看到的是首先绘制的表单,控件所在的位置有孔。这些孔有白色背景。使用 TransparencyKey 或 Opacity 属性时为黑色。然后,每个控件都会获得 Paint 事件,并一个接一个地填充孔。这种效果也被用户感知为闪烁,尽管它与 DoubleBuffered 解决的闪烁不同。当背景为黑色时尤其明显。

解决这个问题需要的是,整个表单及其所有控件都是双缓冲的。这在 Windows 窗体中不可用。但是,Windows XP 和更高版本实际上支持这一点。检查this thread 看看它是如何完成的。请注意,它可能会产生该线程中记录的副作用。

【讨论】:

有趣,虽然在datagridview的情况下,没有双缓冲,重绘控件需要2-3秒,但是双缓冲,它立即出现 顺便说一句,对问题受保护部分的答案投赞成票 实际上双缓冲显着加快了速度……足够快,肉眼可以轻松分辨出差异。我很欣赏这个答案,因为它可能是最“正确”的事情,但它并不像使用反射来设置更改 DataGridView 上的设置那样实用 我的问题是,当我将表单更改为使用此派生类而不是普通类时,资源编辑器将不再显示该表单。【参考方案3】:

根据定义,双缓冲使用两个缓冲区和两倍的内存来呈现控件的视图。所以,那里有一些缺点,但是,以你现在在 PC 中获得的内存量,可能没有多少人会注意到这种牺牲。

不知道为什么它受到保护。也许该功能在控件的早期版本中不可用,并且在引入它时设计人员不想更改控件的公共接口。或者他们认为它是一项高级功能,并希望限制新控制控件的方法的数量,以便能够使其做一些有用的事情。

【讨论】:

【参考方案4】:

turn on doublebuffering on a datagridview 不需要继承。您可以通过反射现有的 datagridview 来做到这一点。

【讨论】:

以上是关于为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Datagridview 中舍入 double 类型的值

点击datagridview的列标题为啥不自动排序

c#字典dictionary绑定datagridview如何排序

为啥Datagridview的最后一行不能排序?

为啥我在 DataGridView 中有问号而不是文本?

为啥显示下拉列表需要在 DataGridView 中单击两次?