在 Windows 窗体应用程序中闪烁

Posted

技术标签:

【中文标题】在 Windows 窗体应用程序中闪烁【英文标题】:Flickering in a Windows Forms app 【发布时间】:2011-03-18 05:08:30 【问题描述】:

我有一个应用程序,上面有大量控件。而且它有大量的闪烁,尤其是在启动时。

我将这个fix 应用到它。

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

效果很好 - 闪烁减少了令人难以置信的数量。但是,副作用是窗口右上角的最小化、最大化和关闭按钮在我将鼠标移到或单击它们时没有动画(尽管它们仍然有效)。这给应用程序一种挂起的感觉。

如何在保留最大化、最小化和关闭按钮可用性的同时保留 WS_EX_COMPOSITED?

这发生在 Windows XP 上。正如@fallenidol 指出的那样,这在 Windows 7 上不是问题。

【问题讨论】:

完美问题(我想要这个功能,我已经尝试过这个解决方案,如何通过这个新约束实现这个功能)。 顺便说一句,我在 Windows 7 上运行的测试应用程序中尝试了此修复,Maximise、Minimize 和 Close 按钮​​似乎仍然动画。 @fallenidol。很高兴知道。我所有的客户都在 XP 上。 我知道这是一篇旧帖子,但是当在 Win 7 SP1 上启用 WS_EX_COMPOSITED 时,最大化、最小化和关闭按钮上的动画消失了。 【参考方案1】:

我想通了。诀窍是在显示表单后删除 WS_EX_COMPOSITED 标志。完整的解释和代码在我的博客:

How to get rid of flicker on Windows Forms applications

【讨论】:

@Hossein 是的,博客暂时关闭了……希望本月的某个时候能恢复。 @Hossein 同时,在这里获取:web.archive.org/web/20160405111506/http://www.angryhacker.com/… 嗨@AngryHacker!我尝试了您的建议,但在 Win 10 中出现闪烁和 MDI 形式的问题。在 Win 7 中,最小化、恢复和关闭按钮上的动画仍然不起作用。你能给我这方面的任何线索吗?提前谢谢你!【参考方案2】:

我刚看到这篇文章,发现它有点老了。但是,我的表单遇到了同样的问题,并且发现(对于 XP,无论如何)一个不优雅的解决方案似乎没有启用视觉样式。

【讨论】:

作为后续,当我覆盖 OnPaintBackground 时,闪烁似乎没有问题。如果我不想绘制背景,我调用 e.Graphics.Clear([适当的颜色]) 并返回,否则调用基本事件方法。正如我所说,这“似乎”缓解了这个问题。但是,我想知道可能会产生哪些不可预见的影响。 更正。只要表单的最小尺寸属性设置为当前尺寸,上述覆盖似乎就可以工作。【参考方案3】:

我知道这个问题有点老了,但迟到总比没有好。我使用了您链接的原始示例,想出了一个在调整大小时将其打开,然后将其关闭以完美绘制其他所有内容的示例。希望它可以帮助其他人寻找解决此问题的方法。正如 OP 所知,DoubleBuffering 单独的属性并不能解决闪烁问题。

这是一种解决方法,可在用户调整表单大小时停止闪烁,但不会弄乱 DataGridView、NumericUpDown 等控件的绘制。前提是您的表单名称为“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;

【讨论】:

好点。我的应用程序中有此代码,但忽略了将其添加到我的博客条目中。过几天会更新。 很好,但是如果我应用此解决方案,那么当调整表单大小时,闪烁又回来了。如果我只是在问题中使用 CreateParams,即使调整表单大小,闪烁也会消失。也许,我错过了什么......【参考方案4】:

试试下面的代码。这应该放在主窗体和您拥有的任何其他自定义用户控件中。

        // Enable double duffering to stop flickering.
        this.SetStyle(ControlStyles.DoubleBuffer, true);
        this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        this.SetStyle(ControlStyles.UserPaint, true);
        this.SetStyle(ControlStyles.SupportsTransparentBackColor, false);
        this.SetStyle(ControlStyles.Opaque, false);
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        this.SetStyle(ControlStyles.ResizeRedraw, true);

【讨论】:

我发布的代码的重点是您只执行一次,而不是针对每个用户控件(有数百个 + 大量的第三方控件)。 对于看到此页面的其他人可能无法访问整个应用程序并且只是单独开发用户控件,这是另一种选择。下次您开发单个用户控件时,您可以使用我上面的代码 sn-p。那么您可能不会遇到有数百个闪烁控件的情况。【参考方案5】:

您应该尝试称为 DoubleBuffered 的标准 Windows 窗体控件属性。 http://msdn.microsoft.com/en-us/library/system.windows.forms.control.doublebuffered.aspx

【讨论】:

这仅适用于每个控件。我提供的示例强制对表单上的每个控件进行双重缓冲。 您可以在应用启动时使用反射来填充每个控件的此属性。 我不能为不公开此属性的第 3 方控件执行此操作。 嗯,任何第三方控件都必须继承自 Windows.Forms.Control。即使此属性已关闭,您也可以使用反射来访问任何私有或受保护的属性。

以上是关于在 Windows 窗体应用程序中闪烁的主要内容,如果未能解决你的问题,请参考以下文章

解决Winform应用程序中窗体背景闪烁的问题

解决Winform应用程序中窗体背景闪烁的问题

在 FlowLayoutPanel 滚动期间,背景扭曲 + 闪烁

winform中panel刷新闪烁的问题

如何在不闪烁和布局重叠的情况下恢复和最大化表单?

实现系统托盘