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,导致窗口不进行绘制。
此时,看到的窗体是假的,现象:

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

转载于:https://www.cnblogs.com/wwlww/p/8410160.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值