当表单获得焦点时,ObjectListView上的黑色背景和工件

时间:2017-02-09 13:51:54

标签: c# winforms tablelayout objectlistview

我在MDI表单上有多个TableLayoutPanels。每个表格布局都有多个控件(包括ObjectListView),只有最顶层设置为可见。

我实现了此SO answer中给出的解决方案,并且在第一次打开表单时效果很好,因为在调整大小时布局的子控件没有闪烁。

我还补充说:

    protected override void OnShown(EventArgs e)
    {
        base.OnShown(e);

        foreach (CoTableLayoutPanel tlp in this.Controls)
        {
            if (tlp != null)
            {
                tlp.BeginUpdate();
                tlp.Size = firstLayout.Size;
                tlp.EndUpdate();
            }
        }
    }

我执行上述操作,以便当我在表单中切换布局时,它们已经是正确的大小,并且在调整大小时避免进一步闪烁。这也很好。

然而,当我对这个派生表格布局进行ObjectListView控制,并且我在表格之间切换时,部分绘制了控件(特别是边框),快速显示黑色背景,最后一列是每次调整大小(列FillsFreeSpace属性)。

如果我使用标准TableLayoutPanel,则列表控件的行为与预期一致,即。没有文物,没有显示黑色背景,没有列调整大小。但是,当我打开表单时,我得到了闪烁。

ObjectListView包含InvalidateRefresh等属性,并且我已尝试在表单的OnGotFocus方法中调用这些属性。问题仍然存在。

这是ObjectListView的问题还是我可以在派生表格布局中解决问题?

修改

问题是由这种方法引起的:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= WS_EX_COMPOSITED;
        return cp;
    }
}

注释掉这个方法会使ObjectListView按预期工作,但闪烁的返回。

上述方法的任何解决方法?

1 个答案:

答案 0 :(得分:2)

显示为黑色的只是窗口的未上漆部分。如果表单上有很多控件,那么重新绘制它们都需要足够的时间来产生明显的工件。当您使用分层窗口时它是黑色的,当您使用Opacity或TransparencyKey属性时会得到一个。如果你不这样做,那么工件往往不那么令人讨厌,因为未上漆的部分往往是白色的。

大多数程序员认为这是一个闪烁问题,但事实并非如此,DoubleBuffered属性无法解决它。抑制它需要使用相同的缓冲区双重缓冲所有控件。大致采用WPF的方法。

双缓冲一切都是WS_EX_COMPOSITED样式标志的作用。纯粹由操作系统完成,不涉及.NET。它是Aero的早期版本,首次在XP上提供。操作系统为顶层窗口创建一个位图,并告诉其控件绘制到该位图而不是直接绘制到视频帧缓冲区。当绘画完成后,它会在一次打击中将位图闪烁到帧缓冲区。不会使绘画更快,但用户认为它非常光滑。如果您现在使用DoubleBuffered属性,则需要将其关闭。

我发现了Winforms btw的技术,10年前已经在MSDN论坛的论坛帖子中首次发布了它。它被复制了许多次,从而像野火一样传播。我没有得到很多关于它的负面反馈,它解决了绝大多数程序员的问题。我所知道的唯一麻烦制造者是TabControl,特别是当它有太多标签并显示左/右导航字形时。它的视觉风格渲染器从来都不是问题,当这些字形出现时,它会重新开始重新绘制。看起来像一个非常快速的闪烁,你不能错过它。易于解决。

所以不,继续前进并使用我的解决方案。这是一个很好的,任何其他方式做这将是非常不重要的。您基本上必须重新发明WPF以完全消除它,使用无窗口控件在父窗口的表面绘制。 VB6做了这个顺便说一句,VB6 UI看起来如此陈旧的一个原因。用代码替换控件也可以让你在那里(Label和PictureBox特别浪费)但是这往往需要大量的代码,你不可能击败3行代码解决方案:)