我在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
包含Invalidate
和Refresh
等属性,并且我已尝试在表单的OnGotFocus
方法中调用这些属性。问题仍然存在。
这是ObjectListView
的问题还是我可以在派生表格布局中解决问题?
修改
问题是由这种方法引起的:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= WS_EX_COMPOSITED;
return cp;
}
}
注释掉这个方法会使ObjectListView
按预期工作,但闪烁的返回。
上述方法的任何解决方法?
答案 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行代码解决方案:)