视觉c#表单更新导致闪烁
本文关键字:闪烁 更新 表单 视觉 | 更新日期: 2023-09-27 17:47:47
我有一个用c#编写的.net应用程序。在某些表单上,我经常更新显示字段。在某些情况下,表单上的每个字段(文本框、标签、图片框等)都会更改其值。此外,变化的频率可能是每秒一次。然而,目前每次更新表单时都会出现可怕的闪烁。我怎样才能停止闪烁?有没有办法让缓冲区加倍?请帮忙!
简短的答案是
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
答案很长:请参阅MSDN或谷歌
为了好玩,在每个元素更新后尝试调用Application.DoEvents(),看看问题是好是坏;-)
这对我有效。
http://www.syncfusion.com/faq/windowsforms/search/558.aspx
基本上,它涉及从所需的控件派生并设置以下样式。
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
您可以尝试调用this.SuspendLayout()在您开始更新之前,并且此。ResumeLayout(false)以这种方式设置完所有值后,应该会阻止表单一次写入一个值。
我知道这个问题已经过时了,但将来其他人可能会搜索它。
DoubleBuffering并不总是能很好地工作。强制表单从不闪烁(但有时会导致绘图问题):
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; //WS_EX_COMPOSITED
return cp;
}
}
当用户调整窗体大小时,要停止闪烁,但又不会打乱控件的绘制(前提是您的窗体名称为"Form1"):
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;
}
您可以用自定义控件替换原始控件,该控件已将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文件进行任何更改。
这也可能是由您的编码引起的,而不是没有双缓冲。我刚刚带着类似的问题来到这里,但意识到这是因为:
- 当项目未被选中时,我将框架设置为不可见
- 在用户选择之间,ListView控件会清除索引
- 我已绑定到SelectedIndexChanged事件
换句话说:
- 用户单击项目1
~选定的索引已更改(1) - 用户单击项目2
~ SelectedIndexChanged(-1)<----这会导致闪烁
~选定的索引已更改(2)
那么解决方案是什么呢?如何避免成千上万不必要的ListView.SelectedIndexChanged事件?
你研究得不好。每个窗体中都有一个DoubleBuffered属性。请尝试将其设置为true。如果你没有在形式绘画上超载任何东西,那么一切都应该正常。
您几乎可以对每个windows窗体控件进行双重缓冲,尽管大多数时候需要从所需控件继承并重写受保护的属性。不过,请注意,我在同一个问题上花了很多时间,我还没有完全消除我更复杂的表单上的闪烁。
如果你想要真正的无闪烁窗口,我建议你看看WPF。
重影通常是由于在单个线程中运行,并且由于字段更新而被搁置,因此绘制事件不会触发。解决这个问题的一种方法是将繁重的工作放在异步方法中。这将允许表单重新绘制自己,并在异步方法回调时更新所需的内容。
我在OpenGLES中遇到了同样的问题,这就是我找到这个线程的原因。当然,我意识到你没有使用ogl,但也许这对你有帮助;)
protected override void OnPaintBackground(PaintEventArgs e)
{
}