如何在窗体上双缓冲 .NET 控件?

发布于 2024-07-05 12:50:17 字数 60 浏览 7 评论 0原文

如何在存在闪烁问题的表单上设置控件的受保护 DoubleBuffered 属性?

How can I set the protected DoubleBuffered property of the controls on a form that are suffering from flicker?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

奢欲 2024-07-12 12:50:18
System.Reflection.PropertyInfo aProp = typeof(System.Windows.Forms.Control)
    .GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic |
    System.Reflection.BindingFlags.Instance);
aProp.SetValue(ListView1, true, null);

Ian 有一些有关使用此功能的更多信息在终端服务器上。

System.Reflection.PropertyInfo aProp = typeof(System.Windows.Forms.Control)
    .GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic |
    System.Reflection.BindingFlags.Instance);
aProp.SetValue(ListView1, true, null);

Ian has some more information about using this on a terminal server.

近箐 2024-07-12 12:50:18
public void EnableDoubleBuffering()
{
   this.SetStyle(ControlStyles.DoubleBuffer | 
      ControlStyles.UserPaint | 
      ControlStyles.AllPaintingInWmPaint,
      true);
   this.UpdateStyles();
}
public void EnableDoubleBuffering()
{
   this.SetStyle(ControlStyles.DoubleBuffer | 
      ControlStyles.UserPaint | 
      ControlStyles.AllPaintingInWmPaint,
      true);
   this.UpdateStyles();
}
守望孤独 2024-07-12 12:50:18

这个很好的解决方案的 vb.net 版本......:

Protected Overrides ReadOnly Property CreateParams() As CreateParams
    Get
        Dim cp As CreateParams = MyBase.CreateParams
        cp.ExStyle = cp.ExStyle Or &H2000000
        Return cp
    End Get
End Property

vb.net version of this fine solution....:

Protected Overrides ReadOnly Property CreateParams() As CreateParams
    Get
        Dim cp As CreateParams = MyBase.CreateParams
        cp.ExStyle = cp.ExStyle Or &H2000000
        Return cp
    End Get
End Property
俯瞰星空 2024-07-12 12:50:18

一种方法是扩展您想要双缓冲的特定控件,并在控件的构造函数内设置 DoubleBuffered 属性。

例如:

class Foo : Panel
{
    public Foo() { DoubleBuffered = true; }
}

One way is to extend the specific control you want to double buffer and set the DoubleBuffered property inside the control's ctor.

For instance:

class Foo : Panel
{
    public Foo() { DoubleBuffered = true; }
}
鹤舞 2024-07-12 12:50:18

nobugz 获得了他的链接中的方法,我只是重新发布。 将此覆盖添加到表单中:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;
        return cp;
    }
}

这对我来说效果最好,在 Windows 7 上,当我调整控件重型表单的大小时,会出现大的黑色块。 控件现在改为弹跳! 但这样更好。

nobugz gets the credit for the method in his link, I'm just reposting. Add this override to the Form:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;
        return cp;
    }
}

This worked best for me, on Windows 7 I was getting large black blocks appearing when I resize a control heavy form. The control now bounce instead! But it's better.

淤浪 2024-07-12 12:50:18

扩展方法打开或关闭控件的双缓冲

public static class ControlExtentions
{
    /// <summary>
    /// Turn on or off control double buffering (Dirty hack!)
    /// </summary>
    /// <param name="control">Control to operate</param>
    /// <param name="setting">true to turn on double buffering</param>
    public static void MakeDoubleBuffered(this Control control, bool setting)
    {
        Type controlType = control.GetType();
        PropertyInfo pi = controlType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
        pi.SetValue(control, setting, null);
    }
}

用法(例如如何使DataGridView DoubleBuffered):

DataGridView _grid = new DataGridView();
//  ...
_grid.MakeDoubleBuffered(true);

Extension method to turn double buffering on or off for controls

public static class ControlExtentions
{
    /// <summary>
    /// Turn on or off control double buffering (Dirty hack!)
    /// </summary>
    /// <param name="control">Control to operate</param>
    /// <param name="setting">true to turn on double buffering</param>
    public static void MakeDoubleBuffered(this Control control, bool setting)
    {
        Type controlType = control.GetType();
        PropertyInfo pi = controlType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
        pi.SetValue(control, setting, null);
    }
}

Usage (for example how to make DataGridView DoubleBuffered):

DataGridView _grid = new DataGridView();
//  ...
_grid.MakeDoubleBuffered(true);
懵少女 2024-07-12 12:50:18

这让我在两天内对第三方控件感到很多的悲伤,直到我找到它。

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;
        return cp;
    }
}

最近,我在重新调整大小/重新绘制包含多个其他控件的控件时遇到了很多漏洞(掉落)。

我尝试了 WS_EX_COMPOSITED 和 WM_SETREDRAW 但没有任何效果,直到我使用这个:

private void myPanel_SizeChanged(object sender, EventArgs e)
{
     Application.DoEvents();
}

只是想传递它。

This caused me a lot of grief for two days with a third party control until I tracked it down.

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;
        return cp;
    }
}

I recently had a lot of holes (droppings) when re-sizing / redrawing a control containing several other controls.

I tried WS_EX_COMPOSITED and WM_SETREDRAW but nothing worked until I used this:

private void myPanel_SizeChanged(object sender, EventArgs e)
{
     Application.DoEvents();
}

Just wanted to pass it on.

镜花水月 2024-07-12 12:50:18

在尝试双缓冲之前,请查看 SuspendLayout()/ResumeLayout() 是否可以解决您的问题。

Before you try double buffering, see if SuspendLayout()/ResumeLayout() solve your problem.

美胚控场 2024-07-12 12:50:18

FWIW

建立在我之前的人的工作之上:
Dummy 的解决方案Ian Boyd 的解决方案Amo 的解决方案

这里是通过 PowerShell 中的 SetStyle 设置双缓冲的版本使用反射

function Set-DoubleBuffered{
<#
.SYNOPSIS
Turns on double buffering for a [System.Windows.Forms.Control] object
.DESCRIPTION
Uses the Non-Public method 'SetStyle' on the control to set the three
style flags recomend for double buffering: 
   UserPaint
   AllPaintingInWmPaint
   DoubleBuffer
.INPUTS
[System.Windows.Forms.Control]
.OUTPUTS
None
.COMPONENT  
System.Windows.Forms.Control
.FUNCTIONALITY
Set Flag, DoubleBuffering, Graphics
.ROLE
WinForms Developer
.NOTES
Throws an exception when trying to double buffer a control on a terminal 
server session becuase doing so will cause lots of data to be sent across 
the line
.EXAMPLE
#A simple WinForm that uses double buffering to reduce flicker
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

$Pen = [System.Drawing.Pen]::new([System.Drawing.Color]::FromArgb(0xff000000),3)

$Form = New-Object System.Windows.Forms.Form
Set-DoubleBuffered $Form
$Form.Add_Paint({
   param(
      [object]$sender,
      [System.Windows.Forms.PaintEventArgs]$e
   )
   [System.Windows.Forms.Form]$f = $sender
   $g = $e.Graphics
   $g.SmoothingMode = 'AntiAlias'
   $g.DrawLine($Pen,0,0,$f.Width/2,$f.Height/2)
})
$Form.ShowDialog()

.LINK
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.setstyle?view=net-5.0
.LINK
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.controlstyles?view=net-5.0
#>
   param(
      [parameter(mandatory=$true,ValueFromPipeline=$true)]
      [ValidateScript({$_ -is [System.Windows.Forms.Control]})]
      #The WinForms control to set to double buffered
      $Control,
      
      [switch]
      #Override double buffering on a terminal server session(not recomended)
      $Force
   )
   begin{try{
      if([System.Windows.Forms.SystemInformation]::TerminalServerSession -and !$Force){
         throw 'Double buffering not set on terminal server session.'
      }
      
      $SetStyle = ([System.Windows.Forms.Control]).GetMethod('SetStyle',
         [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance
      )
      $UpdateStyles = ([System.Windows.Forms.Control]).GetMethod('UpdateStyles',
         [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance
      )
   }catch {$PSCmdlet.ThrowTerminatingError($PSItem)}
   }process{try{
      $SetStyle.Invoke($Control,@(
         ([System.Windows.Forms.ControlStyles]::UserPaint -bor
           [System.Windows.Forms.ControlStyles]::AllPaintingInWmPaint -bor
           [System.Windows.Forms.ControlStyles]::DoubleBuffer
         ),
         $true
      ))
      $UpdateStyles.Invoke($Control,@())
   }catch {$PSCmdlet.ThrowTerminatingError($PSItem)}}
}

FWIW

building on the work of those who've come before me:
Dummy's Solution, Ian Boyd's Solution, Amo's Solution

here is a version that sets double buffering via SetStyle in PowerShell using reflection

function Set-DoubleBuffered{
<#
.SYNOPSIS
Turns on double buffering for a [System.Windows.Forms.Control] object
.DESCRIPTION
Uses the Non-Public method 'SetStyle' on the control to set the three
style flags recomend for double buffering: 
   UserPaint
   AllPaintingInWmPaint
   DoubleBuffer
.INPUTS
[System.Windows.Forms.Control]
.OUTPUTS
None
.COMPONENT  
System.Windows.Forms.Control
.FUNCTIONALITY
Set Flag, DoubleBuffering, Graphics
.ROLE
WinForms Developer
.NOTES
Throws an exception when trying to double buffer a control on a terminal 
server session becuase doing so will cause lots of data to be sent across 
the line
.EXAMPLE
#A simple WinForm that uses double buffering to reduce flicker
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

$Pen = [System.Drawing.Pen]::new([System.Drawing.Color]::FromArgb(0xff000000),3)

$Form = New-Object System.Windows.Forms.Form
Set-DoubleBuffered $Form
$Form.Add_Paint({
   param(
      [object]$sender,
      [System.Windows.Forms.PaintEventArgs]$e
   )
   [System.Windows.Forms.Form]$f = $sender
   $g = $e.Graphics
   $g.SmoothingMode = 'AntiAlias'
   $g.DrawLine($Pen,0,0,$f.Width/2,$f.Height/2)
})
$Form.ShowDialog()

.LINK
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.setstyle?view=net-5.0
.LINK
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.controlstyles?view=net-5.0
#>
   param(
      [parameter(mandatory=$true,ValueFromPipeline=$true)]
      [ValidateScript({$_ -is [System.Windows.Forms.Control]})]
      #The WinForms control to set to double buffered
      $Control,
      
      [switch]
      #Override double buffering on a terminal server session(not recomended)
      $Force
   )
   begin{try{
      if([System.Windows.Forms.SystemInformation]::TerminalServerSession -and !$Force){
         throw 'Double buffering not set on terminal server session.'
      }
      
      $SetStyle = ([System.Windows.Forms.Control]).GetMethod('SetStyle',
         [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance
      )
      $UpdateStyles = ([System.Windows.Forms.Control]).GetMethod('UpdateStyles',
         [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance
      )
   }catch {$PSCmdlet.ThrowTerminatingError($PSItem)}
   }process{try{
      $SetStyle.Invoke($Control,@(
         ([System.Windows.Forms.ControlStyles]::UserPaint -bor
           [System.Windows.Forms.ControlStyles]::AllPaintingInWmPaint -bor
           [System.Windows.Forms.ControlStyles]::DoubleBuffer
         ),
         $true
      ))
      $UpdateStyles.Invoke($Control,@())
   }catch {$PSCmdlet.ThrowTerminatingError($PSItem)}}
}
十雾 2024-07-12 12:50:18

我创建了一个静态方法,它接受 Control 并以递归方式将每个子项的 DoubleBuffered 属性设置为 true

public static void CascadingDoubleBuffer(Control c)
{
    var p = c.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
    p?.SetValue(c, true, null);
    foreach (Control cc in c.Controls) CascadingDoubleBuffer(cc);
}

我使用 DataGridView 创建了一个自定义日历,每次用户与其交互时都会刷新,此方法消除了引起偏头痛的闪烁。

I created a static method that accepts a Control and sets the DoubleBuffered property to true to each and every children recursively.

public static void CascadingDoubleBuffer(Control c)
{
    var p = c.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
    p?.SetValue(c, true, null);
    foreach (Control cc in c.Controls) CascadingDoubleBuffer(cc);
}

I created a custom calendar using DataGridView that refreshes everytime the user interacts with it, this method removes the migraine-inducing flicker.

眼前雾蒙蒙 2024-07-12 12:50:18

您还可以将控件继承到您自己的类中,并在其中设置属性。 如果您倾向于在所有控件上进行大量相同的设置,那么此方法也很好。

You can also inherit the controls into your own classes, and set the property in there. This method is also nice if you tend to be doing a lot of set up that is the same on all of the controls.

无可置疑 2024-07-12 12:50:18

我发现只需在表单上设置 DoubleBuffered 设置就会自动设置此处列出的所有属性。

I have found that simply setting the DoubleBuffered setting on the form automatically sets all the properties listed here.

给不了的爱 2024-07-12 12:50:17

这是Dummy 解决方案的更通用版本。

我们可以使用反射来获取受保护的 DoubleBuffered< /a> 属性,然后可以将其设置为 true

注意:您应该缴纳开发者税 而不是如果用户在终端服务会话中运行则使用双缓冲< /a>(例如远程桌面)如果用户在远程桌面中运行,则此帮助程序方法将不会打开双缓冲。

public static void SetDoubleBuffered(System.Windows.Forms.Control c)
{
   //Taxes: Remote Desktop Connection and painting
   //http://blogs.msdn.com/oldnewthing/archive/2006/01/03/508694.aspx
   if (System.Windows.Forms.SystemInformation.TerminalServerSession)
      return;

   System.Reflection.PropertyInfo aProp = 
         typeof(System.Windows.Forms.Control).GetProperty(
               "DoubleBuffered", 
               System.Reflection.BindingFlags.NonPublic | 
               System.Reflection.BindingFlags.Instance);

   aProp.SetValue(c, true, null); 
}

Here's a more generic version of Dummy's solution.

We can use reflection to get at the protected DoubleBuffered property, and then it can be set to true.

Note: You should pay your developer taxes and not use double-buffering if the user is running in a terminal services session (e.g. Remote Desktop) This helper method will not turn on double buffering if the person is running in remote desktop.

public static void SetDoubleBuffered(System.Windows.Forms.Control c)
{
   //Taxes: Remote Desktop Connection and painting
   //http://blogs.msdn.com/oldnewthing/archive/2006/01/03/508694.aspx
   if (System.Windows.Forms.SystemInformation.TerminalServerSession)
      return;

   System.Reflection.PropertyInfo aProp = 
         typeof(System.Windows.Forms.Control).GetProperty(
               "DoubleBuffered", 
               System.Reflection.BindingFlags.NonPublic | 
               System.Reflection.BindingFlags.Instance);

   aProp.SetValue(c, true, null); 
}
北方的巷 2024-07-12 12:50:17

检查此线程

重复该答案的核心,您可以打开窗口上的 WS_EX_COMPOSITED 样式标志,以使表单及其所有控件都得到双缓冲。 样式标志自 XP 起可用。 它不会使绘画速度更快,但整个窗口都会在屏幕外缓冲区中绘制,并一口气传输到屏幕上。 使其在用户眼中看起来是即时的,而没有明显的绘画伪影。 它并非完全没有问题,某些视觉样式渲染器可能会出现故障,特别是当 TabControl 有太多选项卡时。 YMMV。

将此代码粘贴到您的表单类中:

protected override CreateParams CreateParams {
    get {
        var cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;    // Turn on WS_EX_COMPOSITED
        return cp;
    } 
}

此技术与 Winform 的双缓冲支持之间的最大区别在于 Winform 的版本一次仅适用于一个控件。 您仍然会看到每个单独的控件绘画本身。 这也可能看起来像闪烁效果,特别是当未绘制的控制矩形与窗口背景形成鲜明对比时。

Check this thread

Repeating the core of that answer, you can turn on the WS_EX_COMPOSITED style flag on the window to get both the form and all of its controls double-buffered. The style flag is available since XP. It doesn't make painting faster but the entire window is drawn in an off-screen buffer and blitted to the screen in one whack. Making it look instant to the user's eyes without visible painting artifacts. It is not entirely trouble-free, some visual styles renderers can glitch on it, particularly TabControl when its has too many tabs. YMMV.

Paste this code into your form class:

protected override CreateParams CreateParams {
    get {
        var cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;    // Turn on WS_EX_COMPOSITED
        return cp;
    } 
}

The big difference between this technique and Winform's double-buffering support is that Winform's version only works on one control at at time. You will still see each individual control paint itself. Which can look like a flicker effect as well, particularly if the unpainted control rectangle contrasts badly with the window's background.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文