我有以下问题:我在表单中放置了一个拆分器控件(不是拆分容器)并添加了 2 个面板。分离器工作正常,但是当我移动分配器时,它开始闪烁 - 面板没有。
我用拆分容器得到相同的结果。
我试过这个,但没有任何效果
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.DoubleBuffered = true;
...
class XSplitter : Splitter
{
public XSplitter() : base()
{
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.DoubleBuffered = true;
}
}
class XPanel : Panel
{
public XPanel() : base()
{
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.DoubleBuffered = true;
}
}
我使用 Windows 8.1 和 VS 2010
谢谢你的帮助!
以下是使用此控件的步骤:
- 将新类"NonFlickerSplitContainer"添加到 C# 应用程序中。
- 将自动生成的类代码替换为如下所示的 C# 代码。
-
在应用程序中使用 NonFlickerSplitContainer 对象而不是 SplitContainer 对象。
public partial class NonFlickerSplitContainer : SplitContainer { public NonFlickerSplitContainer() { this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true); MethodInfo objMethodInfo = typeof(Control).GetMethod("SetStyle",BindingFlags.NonPublic|BindingFlags.Instance); object[] objArgs = new object[] { ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true }; objMethodInfo.Invoke(this.Panel1, objArgs); objMethodInfo.Invoke(this.Panel2, objArgs); } }
查看拆分器源代码 - http://referencesource.microsoft.com
-
拆分器使用来自WM_PAINT外部的 GDI 调用,利用父级(非自己的)设备上下文:
private void DrawSplitHelper(int splitSize) { ... IntPtr parentHandle = ParentInternal.Handle; IntPtr dc = UnsafeNativeMethods.GetDCEx(new HandleRef(ParentInternal, parentHandle), NativeMethods.NullHandleRef, NativeMethods.DCX_CACHE | NativeMethods.DCX_LOCKWINDOWUPDATE); IntPtr halftone = ControlPaint.CreateHalftoneHBRUSH(); ...
所以样式设置没有任何影响。
-
当拆分器移动时,它会从先前的位置删除图像,然后再在新位置绘制:
private void DrawSplitBar(int mode) { if (mode != DRAW_START && lastDrawSplit != -1) { DrawSplitHelper(lastDrawSplit); lastDrawSplit = -1; ...
如果此时屏幕刷新,您会看到闪烁。
-
Windows 窗体是在那些年开发的,当时大多数人使用 CRT 监视器,半色调画笔(参见上文)看起来很平滑。如今,即使在静态图像上,一些LCD显示器也会闪烁。
解决方案是创建实心画笔而不是半色调画笔:
var brush = default(LOGBRUSH);
brush.lbColor = 0x2A2A2A; // Invert alternate bits except highest: ..#.#.#.
并在移动时仅重绘差异矩形:
private void DrawSplitBar(int mode)
{
...
if (mode != DRAW_END)
{
var rect = newRect;
SubtractRect(out newRect, ref newRect, ref oldRect);
SubtractRect(out oldRect, ref oldRect, ref rect);
}
DrawSplitHelper(oldRect);
...
在 https://gist.github.com/ArtemAvramenko/e260420b86564cf13d2e 查看我的解决方案