visual c#form update导致闪烁

时间:2008-10-08 04:42:33

标签: c# winforms

我有一个.net应用程序,我用c#编写。在某些形式上,我经常更新显示字段。在某些情况下,表单上的每个字段(文本框,标签,图片框等)都会更改其值。此外,变化的频率可能是每秒。但是,目前每次更新表单时都会出现可怕的闪烁现象。怎么能阻止闪烁?有没有办法可能加倍缓冲?请帮忙!

10 个答案:

答案 0 :(得分:7)

简短的回答是

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

答案很长:请参阅MSDNgoogle

只是为了好玩,尝试在每个元素更新后调用Application.DoEvents(),看看问题是好还是坏; - )

答案 1 :(得分:5)

这对我有用。

http://www.syncfusion.com/faq/windowsforms/search/558.aspx

基本上它涉及从所需的控件派生并设置以下样式。

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

答案 2 :(得分:4)

您可以尝试在开始更新之前调用 this.SuspendLayout(); ,并在完成设置所有值后 this.ResumeLayout(false); 这样就可以防止表单一次写一个值。

答案 3 :(得分:3)

我知道这个问题已经过时了,但未来其他人可能会搜索它。

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;
}

答案 4 :(得分:2)

您可以将原始控件替换为具有受保护DoubleBuffered属性的自定义控件。例如。对于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文件不需要更改。

答案 5 :(得分:2)

它也可能是由您的编码引起的,而不是没有双重缓冲。我刚才带着类似的问题来到这里,但意识到这是因为:

  1. 当未选择项目时,我将框架设置为不可见。
  2. 在用户选择之间,ListView控件将清除索引。
  3. 我已经绑定了SelectedIndexChanged事件
  4. 换句话说:

    • 用户点击第1项 ~SelectedIndexChanged(1)
    • 用户点击第2项 ~SelectedIndexChanged(-1)< ----这导致闪烁
      ~SelectedIndexChanged(2)

    那么解决方案是什么? How to avoid thousands of needless ListView.SelectedIndexChanged events?

答案 6 :(得分:1)

你没有好好研究这个问题。每个表单中都有一个DoubleBuffered属性。尝试将其设置为true。如果你没有在表格绘画上重载任何东西,那么一切都应该有效。

答案 7 :(得分:1)

您可以double buffer几乎每个窗体都可以控制,但大多数情况下它需要您从所需的控件继承并覆盖受保护的属性。但要注意的是,我在相同的问题上花了很多时间,而且我还没有完全消除更复杂形式的闪烁。

如果您想要真正无闪烁的窗口,我建议您查看WPF。

答案 8 :(得分:0)

重影通常是因为你在单个线程中运行而且它被字段更新阻止,所以paint事件不会触发。解决这个问题的一种方法是将繁重的工作放在异步方法中。这将允许表单重新绘制自己并更新异步方法回调时所需的内容。

答案 9 :(得分:0)

我遇到了与OpenGLES相同的问题,这就是我发现这个帖子的方法。 当然我意识到你没有使用ogl,但也许这对你有帮助;)

protected override void OnPaintBackground(PaintEventArgs e) { }