避免Windows Forms中的闪烁问题?

9

组合框无法使用双缓冲。在Windows窗体中,有没有其他方法可以避免闪烁?

我有一个Windows窗体,其中包含多个面板。根据我的菜单选择,我只显示一个面板。

我有一个图标面板、一个标题面板和一个组合框。根据该组合框所选项目,填充GridView1和2。当我使用键盘向下箭头快速选择组合框项目时,图标面板和标题面板始终重新绘制。我需要保持这两个面板不变。这两个面板会产生一些闪烁效果(即它们会闪烁或闪烁),而我正在更改组合框的选定索引。有没有办法避免这种闪烁?我尝试在表单构造器和表单加载事件中启用双缓冲,但没有成功。

InitializeComponent();
                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);

我尝试在表单构造函数和表单加载事件中使用了这段代码。

这些都不相关..使用此自定义控件来自https://dev59.com/sWkv5IYBdhLWcg3wwjkI。 - user1812146
3个回答

36

另一种解决方案:

//TODO: Don't forget to include using System.Runtime.InteropServices.

internal static class NativeWinAPI
{
    internal static readonly int GWL_EXSTYLE = -20;
    internal static readonly int WS_EX_COMPOSITED = 0x02000000;

    [DllImport("user32")]
    internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32")]
    internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
}

你的表单构造函数应该如下所示:

public MyForm()
{
    InitializeComponent();

    int style = NativeWinAPI.GetWindowLong(this.Handle, NativeWinAPI.GWL_EXSTYLE);
    style |= NativeWinAPI.WS_EX_COMPOSITED;
    NativeWinAPI.SetWindowLong(this.Handle, NativeWinAPI.GWL_EXSTYLE, style);
}

在上面的代码中,您可以将this.Handle更改为MyFlickeringPanel.Handle之类的内容。
您可以在这里阅读更多相关信息:扩展窗口样式CreateWindowEx

使用WS_EX_COMPOSITED设置后,窗口的所有子项都使用双缓冲技术按照从底部到顶部的绘画顺序进行绘制。从底部到顶部的绘画顺序允许子窗口具有半透明(alpha)和透明度(color-key)效果,但前提是子窗口还设置了WS_EX_TRANSPARENT位。双缓冲技术使窗口及其子项无闪烁地绘制。


我没有足够的声望来点赞这个答案,所以我没有点赞。抱歉…… - ManjuVijayan
@Khil 我曾经遇到这个问题,这个方法非常有效。我的应用一直在闪烁,所以我尝试了这个方法后就不再闪烁了。但是,我发现此机器上的其他窗口也出现了同样的情况。一开始我没有注意到这一点,因为我一直专注于我的应用程序。我仍然不知道为什么这台机器上的每个窗口都在闪烁,但我确信我的应用程序是唯一没有闪烁的。 - Jake
2
对于 MyFlickeringPanel.Handle 执行加1操作。 - Mirjalal
1
感谢使用MyFlickeringPanel.Handle - Gustavo Marin Suppi

4
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams handleParam = base.CreateParams;
            handleParam.ExStyle |= 0x02000000;   // WS_EX_COMPOSITED       
            return handleParam;
        }
    }

2

解决方案1:
在添加项目之前使用ComboxBox.BeginUpdate()。这将防止每次向列表中添加项目时Control重新绘制ComboBox。添加完项目后,您可以使用ComboBox.EndUpdate()进行重绘。

解决方案2:

private void EnableDoubleBuffering()
{
    this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
}

在Page_load或New()中调用EnableDoubleBuffering()? - Rohan Rao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接