C# Windows Forms: Splitter flickering

2019-10-18 22:41发布

我有以下问题:我在形式置于一分段控制(未分裂容器)中并加入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

THX的帮助!

Answer 1:

下面是使用该控件的步骤:

  • 新阶级“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); } } 


Answer 2:

看看分离器的源代码- http://referencesource.microsoft.com

  1. 分路器借鉴了父母的(不是自己的)设备上下文,使用GDI从WM_PAINT的外线电话:

     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. 当分配器移动时,它会从以前的位置像在新的地方绘制前:

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

    如果屏幕刷新在这一刻,你看到的闪烁。

  3. Windows窗体在这些年的发展,当大多数人使用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



文章来源: C# Windows Forms: Splitter flickering