我有一个用c#编写的.net应用程序,在一些表单上频繁更新显示字段。在某些情况下,表单上的每个字段(文本框、标签、图片框等)都会更改其值。而且更改的频率可能每秒钟一次。然而,当前每次更新表单时都会出现可怕的闪烁。我该如何停止闪烁?是否有一种方法可以使用双缓冲区?请帮忙!
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
我知道这个问题已经很久了,但也许将来还有人会搜索到它。
双缓冲并不总是起作用的。如果要强制窗体根本不闪烁(但有时可能会导致绘图问题):
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; //WS_EX_COMPOSITED
return cp;
}
}
int intOriginalExStyle = -1;
bool bEnableAntiFlicker = true;
public Form1()
{
ToggleAntiFlicker(false);
InitializeComponent();
this.ResizeBegin += new EventHandler(Form1_ResizeBegin);
this.ResizeEnd += new EventHandler(Form1_ResizeEnd);
}
protected override CreateParams CreateParams
{
get
{
if (intOriginalExStyle == -1)
{
intOriginalExStyle = base.CreateParams.ExStyle;
}
CreateParams cp = base.CreateParams;
if (bEnableAntiFlicker)
{
cp.ExStyle |= 0x02000000; //WS_EX_COMPOSITED
}
else
{
cp.ExStyle = intOriginalExStyle;
}
return cp;
}
}
private void Form1_ResizeBegin(object sender, EventArgs e)
{
ToggleAntiFlicker(true);
}
private void Form1_ResizeEnd(object sender, EventArgs e)
{
ToggleAntiFlicker(false);
}
private void ToggleAntiFlicker(bool Enable)
{
bEnableAntiFlicker = Enable;
//hacky, but works
this.MaximizeBox = true;
}
在开始更新之前,您可以尝试调用this.SuspendLayout();,并在设置完所有值后使用this.ResumeLayout(false);,这样做可以防止表单逐个写入值。
您可以将原始控件替换为自定义控件,该控件具有保护的DoubleBuffered属性设置为true。例如,对于ListView,代码如下:
internal class DoubleBufferedListView : ListView {
public DoubleBufferedListView()
: base() {
this.DoubleBuffered = true;
}
}
之后,您只需访问*.Designer.cs文件,并将所有对原生控件的提及替换为此控件。
P.S. 您也可以通过反射设置此属性,而无需继承自控件:
listView1.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(lsvReport, true, null);
虽然不太干净也不建议这样做,但是它不需要对*.Designer.cs文件进行任何更改。
你没有做好研究。每个窗体中都有一个DoubleBuffered属性,请尝试将其设置为true。如果您没有在窗体绘图方面进行过载,则一切都应该正常工作。
你可以将几乎所有的 Windows Forms 控件 双缓冲,尽管大多数情况下需要从所需的控件继承并重写一个受保护的属性。不过要小心,因为我在同样的问题上花了很多时间,但仍然无法完全消除我更复杂表单的闪烁。
如果你想要真正无闪烁的窗口,我建议看一下 WPF。
通常情况下,出现幽灵图像的原因是因为您正在单线程中运行,并且由于字段更新而被阻塞,因此绘制事件无法触发。解决这个问题的一种方法是将繁重的工作放在异步方法中。这将允许窗体重新绘制自身并在异步方法回调时更新所需的任何内容。