【问题标题】:visual c# form update results in flickeringvisual c# 表单更新导致闪烁
【发布时间】:2010-09-15 22:23:35
【问题描述】:

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

【问题讨论】:

    标签: c# winforms


    【解决方案1】:

    简短的回答是

    SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
    

    长答案是:见MSDNgoogle

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

    【讨论】:

    • 我不确定这会有所帮助。听起来问题在于标准控件闪烁,OptimizedDoubleBuffer 只会帮助自定义呈现的控件。
    【解决方案2】:

    这对我有用。

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

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

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

    【讨论】:

    • 这应该是答案!
    【解决方案3】:

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

    【讨论】:

    • suspendlayout/resumelayout 用于抑制与添加和移动控件相关的事件
    • 正确,这些事件仅防止在更新大量控件时多次调用布局函数。因此,这些功能将加快布局,但不会防止闪烁。将它们与双缓冲结合使用将产生最佳效果。
    【解决方案4】:

    我知道这个问题很老,但将来可能会有其他人搜索它。

    双缓冲并不总是很好用。强制表单从不闪烁(但有时会导致绘图问题):

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

    【讨论】:

    • 这是最好的,在我看来是明确的答案。
    【解决方案5】:

    您可以将原始控件替换为将 DoubleBuffered 属性保护为 true 的自定义控件。例如。对于 ListView,它会是这样的:

    internal class DoubleBufferedListView : ListView {
    
        public DoubleBufferedListView()
            : base() {
            this.DoubleBuffered = true;
        }
    
    }
    

    之后,您只需访问 *.Designer.cs 文件并将所有提及的本机控件替换为该文件。

    附:除了从控件继承之外,您还可以通过反射设置此属性:

    listView1.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(lsvReport, true, null);
    

    它不干净也不推荐,但它不需要更改 *.Designer.cs 文件。

    【讨论】:

      【解决方案6】:

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

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

      换句话说:

      • 用户点击项目 1
        ~ SelectedIndexChanged(1)
      • 用户点击项目 2
        ~ SelectedIndexChanged(-1) ~ SelectedIndexChanged(2)

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

      【讨论】:

        【解决方案7】:

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

        【讨论】:

        • 谢谢!我花了很长时间寻找这个,它一直坐在我面前。
        【解决方案8】:

        您可以double buffer 几乎每个 Windows 窗体控件,尽管大多数时候它要求您从所需的控件继承并覆盖受保护的属性。不过请注意,我在同一个问题上花了很多时间,但我还没有完全消除我更复杂的表单上的闪烁。

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

        【讨论】:

          【解决方案9】:

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

          【讨论】:

            【解决方案10】:

            我在使用 OpenGLES 时遇到了同样的问题,这就是我找到这个线程的方式。 当然,我意识到你没有使用 ogl,但也许这对你有帮助;)

            protected override void OnPaintBackground(PaintEventArgs e) { }

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2016-08-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-10-08
              • 1970-01-01
              相关资源
              最近更新 更多