1

我有以下问题:我在表单中放置了一个拆分器控件(不是拆分容器)并添加了 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

谢谢帮助!

4

2 回答 2

3

以下是使用此控件的步骤:

  • 将新类“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);
       }
    }
    
于 2014-02-25T10:45:57.203 回答
0

查看 Splitter 源代码 - http://referencesource.microsoft.com

  1. Splitter 使用来自 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();
      ...
    

    所以样式设置没有任何效果。

  2. 当 Splitter 移动时,它会在新位置绘制之前从先前位置移除图像:

    private void DrawSplitBar(int mode) {
      if (mode != DRAW_START && lastDrawSplit != -1) {
        DrawSplitHelper(lastDrawSplit);
        lastDrawSplit = -1;
      ...
    

    如果此时屏幕刷新,您会看到闪烁。

  3. Windows Forms 是在那些年开发的,当时大多数人使用 CRT 显示器,并且半色调画笔(参见上文)看起来很平滑。这些天来,一些液晶显示器即使在静态图片上也会闪烁。

解决方案是创建实心画笔而不是半色调之一:

    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查看我的解决方案

于 2015-07-29T22:10:14.280 回答