zoukankan      html  css  js  c++  java
  • Winform MDI窗体切换不闪烁的解决办法(测试通过)

     MDI窗体不闪烁方法测试通过:


    //.net 4.0用OptimizedDoubleBuffer
    this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint |  ControlStyles.AllPaintingInWmPaint, true);
    this.UpdateStyles();

    真正有效的方法:在最上层窗体加上
    protected override CreateParams CreateParams {
      get {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
        return cp;
      }


    在下层的窗体和自定义控件加上
    protected override CreateParams CreateParams
            {
                get
                {
                    CreateParams cp = base.CreateParams;
                    cp.Style &= ~0x02000000;  // Turn off WS_CLIPCHILDREN 
                    return cp;
                }
            }  

    注意:如果加错地方或人品不好,某些时候可能会造成控件绘制略微不正常。

    **** 如果人品爆发的话,貌似在下层窗体直接加cp.Style &= ~0x02000000就行,不需要在上层窗体加cp.ExStyle |= 0x02000000;

    **** 注意下层窗体代码在ListBox或者ListView的Anchor设有Right,且窗体BackColor与控件背景不同的时候,可能会发现控件初始化显示不正常。需要做一下MdiParent.Refresh或者取消Right

    引用MSDN中对CreateParams的说明:
        在你开发的重载控件中不要重写这个属性,通过这个属性控制控件的某些风格。只有在你封装Windows控件或者想实现某些WinForm没有提供的风格(比如Layered Window)控制的时候再使用这个属性。更多信息请参照MSDN上对CreateWindow方法和CreateWindowEx方法的参数CREATESTRUCT结构体的文档注释 。
    简述为何CreateParams能够实现这样高级的样式控制,因为从CreateWindow和CreateWindowEx的名字就可以看出,CreateParam是传递给这俩个方法的参数,而这两个方法又是在窗体创建的时候调用的。所以,CreateParam才能够实现如此强大的样式控制。

    节点更新要使用BeginUpdate和EndUpdate
          这一对操作对于需要批量操作更新控件的情景有比较好的效果,比如初始化时批量添加了大量节点。坏处就在于不能即时更新。所以,对于频繁的更新节点并希望立即反映到界面的情况不适用。如果使用并且没有禁掉清除界面消息的话,则控件看起来就会不停的闪烁,而且以白底为主,内容几乎不可见(这个视频繁程度而定)。因为界面更新都在EndUpdate处完成,操作太多导致EndUpdate阻塞时间过长,且清空在先,更新在后,导致界面看起来长时间处于空白状态。

    某些情况下可以使用禁止背景更新
    protected override void WndProc(ref Message m)
            {
                if (m.Msg == 0x0014)  return;// 禁掉清除背景消息 
                base.WndProc(ref m);
            }

    public ListViewNF()
            {
                // 开启双缓冲
                this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

                // Enable the OnNotifyMessage event so we get a chance to filter out 
                // Windows messages before they get to the form's WndProc
                this.SetStyle(ControlStyles.EnableNotifyMessage, true);
            }

            protected override void OnNotifyMessage(Message m)
            {
                //Filter out the WM_ERASEBKGND message
                if (m.Msg != 0x14)
                {
                    base.OnNotifyMessage(m);
                }
            }

    ******************************************

     采用LockWindowUpdate API

     [DllImport("user32.dll")]
    static extern bool LockWindowUpdate(IntPtr hWndLock);

    LockWindowUpdate(panelContainer.Handle);

    // Clear Panel
    panelContainer.Controls.Clear();

    // my temporary TextBox
    TextBox myT ;

    for (int lauf=0; lauf < 200; lauf++)
    {
        // Create New TextBox
        myT = new TextBox();

        // Add TextBox to the Panel
        panelContainer.Controls.Add(myT);
    }
    // redraw the window
    LockWindowUpdate(IntPtr.Zero);

    frmChild1.Hide( ); // 隐藏当前显示的子窗体2 3 LockWindowUpdate(this.Handle); // 锁定父窗体4 frmChild2.Show( ); // 显示窗体等其他需要再显示前做的事5 LockWindowUpdate (IntPtr.Zero); // 解锁父窗体6 RedrawWindow (this.Handle, IntPtr.Zero, IntPtr.Zero, 
      RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN); // (0x04 | 0x01 | 0x80)立即强制重绘父窗体及其所有子窗体

        效果好转,但人眼还能看到一些花屏现象,仍不能一次全部完整显示。

      

    3. 使用Windows API中的SendMessage函数: 

    拦截控件重绘
    class DrawingControl
    {
        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);
     
        private const int WM_SETREDRAW = 11; 
     
        public static void SuspendDrawing( Control parent )
        {
            SendMessage(parent.Handle, WM_SETREDRAW, false, 0);
        }
     
        public static void ResumeDrawing( Control parent )
        {
            SendMessage(parent.Handle, WM_SETREDRAW, true, 0);
            parent.Refresh();
        }
    }
    复制代码
    1 frmChild1.Hide( );2 3 SendMessage(this.Handle, WM_SETDRAW, false, null); // 禁止窗体中的绘制操作 ----- 14 frmChild2.Show( ); // 显示窗体等其他需要再显示前做的事5 SendMessage(this.Handle, WM_SETDRAW, true, null); // 解除禁止绘制操作 ----- 26 RedrawWindow (this.Handle, IntPtr.Zero, IntPtr.Zero, 
      RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN); // (0x04 | 0x01 | 0x80)立即强制重绘父窗体及其所有子窗

    SendMessage函数中,发送消息 WM_SETREDRAW设置SETREDRAW为FALSE,导致窗口不进行绘制。
    此时,看到的窗体是假的,现象:

    鼠标形状是后面应用程序的形状;
    鼠标划过,后面的应用程序就显示出来了。
    人眼看到的就是“花屏”。

  • 相关阅读:
    20155313 杨瀚 《网络对抗技术》实验九 Web安全基础
    20155313 杨瀚 《网络对抗技术》实验八 Web基础
    20155313 杨瀚 《网络对抗技术》实验七 网络欺诈防范
    20155313 杨瀚 《网络对抗技术》实验六 信息搜集与漏洞扫描
    20155313 杨瀚 《网络对抗技术》实验五 MSF基础应用
    20155313 杨瀚 《网络对抗技术》实验四 恶意代码分析
    20155313 杨瀚 《网络对抗技术》实验三 免杀原理与实践
    20155313 杨瀚 《网络对抗技术》实验二 后门原理与实践
    20155313 杨瀚 《网络对抗技术》实验一 PC平台逆向破解(5)M
    20155313 2017-2018-1 《信息安全系统设计基础》课程总结
  • 原文地址:https://www.cnblogs.com/wwlww/p/8410160.html
Copyright © 2011-2022 走看看