一尘不染

如何解决用户控件中的闪烁

c#

在我的应用程序中,我不断地从一个控件转移到另一个控件。我没有创建。用户控件,但在导航过程中我的控件会闪烁。更新需要1或2秒。我试图设置这个

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
or
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); 
SetStyle(ControlStyles.DoubleBuffer, true);

但这无济于事…每个控件都有相同的背景图像,但控件不同。那么解决方案是什么..
谢谢。


阅读 311

收藏
2020-05-19

共1个答案

一尘不染

这不是双缓冲可以解决的那种闪烁。也没有BeginUpdate或SuspendLayout。你有太多的控制,和backgroundImage可以把它 很多
更坏。

它在UserControl绘制自身时开始。它绘制BackgroundImage,在子控件窗口所在的位置留下孔。然后,每个子控件都会获得一条消息以对其进行绘制,然后将其窗口内容填充到孔中。当您有许多控件时,这些孔在一段时间内对用户可见。它们通常是白色的,与黑暗时的BackgroundImage形成鲜明对比。或者,如果表单设置了Opacity或TransparencyKey属性,则它们可以是黑色的,与几乎任何东西都形成鲜明对比。

这是Windows窗体的一个非常基本的限制,它与Windows渲染窗口的方式紧密相关。由WPF
btw修复,它不将窗口用于子控件。您想要的是对整个表单(包括子控件)进行双缓冲。可能的话,请在此线程中检查我的代码以获取解决方案。虽然它有副作用,但实际上并没有提高绘画速度。代码很简单,将其粘贴到您的表单中(而不是用户控件):

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

您可以采取许多措施来提高绘画速度,以至于不再出现闪烁。首先处理BackgroundImage。当源图像很大并且需要缩小以适合控件时,它们可能 真的很
昂贵。将BackgroundImageLayout属性更改为“
Tile”。如果这样可以显着提高速度,请返回到绘画程序并调整图像大小,使其与典型控件尺寸更好地匹配。或在UC的OnResize()方法中编写代码以创建适当大小的图像副本,这样就不必在每次重新绘制控件时都调整其大小。对于该副本使用Format32bppPArgb像素格式,它的渲染速度比任何其他像素格式快10倍。

接下来,您可以做的是防止孔洞变得如此明显并与图像形成鲜明对比。您可以关闭
UC的WS_CLIPCHILDREN样式标志,该标志可防止UC在子控件所在的区域绘画。将此代码粘贴到UserControl的代码中:

protected override CreateParams CreateParams {
  get {
    var parms = base.CreateParams;
    parms.Style &= ~0x02000000;  // Turn off WS_CLIPCHILDREN
    return parms;
  }
}

子控件现在将自己绘制在背景图像上。您可能仍会看到他们一张一张地画自己,但是看不见难看的中间白色或黑色孔。

最后但并非最不重要的一点是,减少子控件的数量始终是解决绘画缓慢问题的好方法。重写UC的OnPaint()事件并绘制现在在子级中显示的内容。特殊的Label和PictureBox
非常 浪费。方便点击,但是它们的轻量级选择(绘制字符串或图像)在OnPaint()方法中仅需一行代码。

2020-05-19