https://stackoverflow.com/questions/5817632/beginupdate-endupdate-for-datagridview-request

SuspendLayout()并且ResumeLayout()不要暂停绘图,只能暂停布局操作。给这个家伙一个机会:

public static class ControlHelper
{
#region Redraw Suspend/Resume
[DllImport("user32.dll", EntryPoint = "SendMessageA", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
private const int WM_SETREDRAW = 0xB; public static void SuspendDrawing(this Control target)
{
SendMessage(target.Handle, WM_SETREDRAW, 0, 0);
} public static void ResumeDrawing(this Control target) { ResumeDrawing(target, true); }
public static void ResumeDrawing(this Control target, bool redraw)
{
SendMessage(target.Handle, WM_SETREDRAW, 1, 0); if (redraw)
{
target.Refresh();
}
}
#endregion
}

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才能够实现如此强大的样式控制。

**********

由于窗体上控件多,且有背景的情况下,控件设为背景设为透明,会导致窗体的刷新很慢很卡,从而窗体在闪烁,卡顿。

之前一直在网上搜寻解决的办法,试过了很多什么双缓冲啊之类的,发现效果并不大。

最后找到下面的方法可以解决了。但是奇怪的是,在有些电脑上运行时会发生窗体不刷新的问题。然后就参考下面的那个网址,最下面的答案。

http://stackoverflow.com/questions/5859826/datagridview-draws-wrong

个人总结一下,可能是系统版本的问题所导致的。网上有说是因为“xp特有的双缓冲绘图机制”。后来用上这个WS_EX_COMPOSITED(用双缓冲从下到上绘制窗口的所有子孙),再开启窗体的透明样式,问题都解决了。

protected override CreateParams CreateParams
{
get
{

CreateParams cp = base.CreateParams;

cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED

if (this.IsXpOr2003 == true)
{
cp.ExStyle |= 0x00080000; // Turn on WS_EX_LAYERED
this.Opacity = 1;
}

return cp;

}

} //防止闪烁

private Boolean IsXpOr2003
{
get
{
OperatingSystem os = Environment.OSVersion;
Version vs = os.Version;

if (os.Platform == PlatformID.Win32NT)
if ((vs.Major == 5) && (vs.Minor != 0))
return true;
else
return false;
else
return false;
}
}

**********

节点更新要使用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( );              // 隐藏当前显示的子窗体

 LockWindowUpdate(this.Handle);  // 锁定父窗体
frmChild2.Show( ); // 显示窗体等其他需要再显示前做的事
LockWindowUpdate (IntPtr.Zero); // 解锁父窗体
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();
    }
}
 frmChild1.Hide( );

 SendMessage(this.Handle, WM_SETDRAW, false, null);  // 禁止窗体中的绘制操作 ----- 
frmChild2.Show( ); // 显示窗体等其他需要再显示前做的事
SendMessage(this.Handle, WM_SETDRAW, true, null); // 解除禁止绘制操作 ----- 2
RedrawWindow (this.Handle, IntPtr.Zero, IntPtr.Zero,
   RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN); // (0x04 | 0x01 | 0x80)立即强制重绘父窗体及其所有子窗

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


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

 

Winform MDI窗体切换不闪烁的解决办法(测试通过)的更多相关文章

  1. Xcode6.1模拟器ios8.1模拟器不能弹出虚拟键盘及虚拟键盘无法切换中文输入的解决办法

    1.不能弹出虚拟键盘的解决办法 模拟器菜单Hardware->Keyboard->Connect Hardware Keyboard取消选中,快捷键commad+shift+K 2.虚拟键 ...

  2. c# winform中窗体切换后释放及防止重复生成

    问题1:窗体切换后如何关闭,并释放资? c# winform中,2个窗体,form1和form2,互相切换的时候执行 this.Hide(); Form2 form2 = new Form2(); f ...

  3. Winform MDI窗体容器、权限、简单通讯

    MDI窗体容器: 一般来说,窗体是顶级容器,不允许放在其他任何容器内,但是如果将某个窗体的IsMdiContainer属性设置为True,那此窗体就会成为窗体容器,可以在其中放入其他窗体 在内部的窗体 ...

  4. Winform MDI窗体容器,权限以及简单通讯

    MDI窗体容器: 一般来说,窗体是顶级容器,不允许放在其他任何容器内,但是如果将某个窗体的IsMdiContainer属性设置为True,那此窗体就会成为窗体容器,可以在其中放入其他窗体 在内部的窗体 ...

  5. Winform MDI窗体容器 权限 简单通讯

    MDI窗体容器 权限  using System; using System.Collections.Generic; using System.ComponentModel; using Syste ...

  6. winform 多线程中ShowDialog()步骤无效的解决办法

    private void Form1_Load(object sender, EventArgs e) { Thread thread = new Thread(remind); thread.IsB ...

  7. phpStudy2018 在win7下切换php7不成功解决办法

    phpstudy 由2016升级到2018后,在切换版本时,php5.6及以下版本可以正常切换,切换7.0以上的版本时访问页面报 0xc000007b 错误,网上找了很多方法都没能解决,最后发现是没装 ...

  8. Oracle在linux下命令行无法使用退格键退格,无法使用上下键切换历史命令的解决办法

    使用xshell等客户端登录oracl时在命令行无法使用退格键也无法使用上下键切换历史命令可以使用rlwrap解决 1,linux环境 2,下载rlwrap wget http://files.cnb ...

  9. vue、react等SPA应用页脚组件闪烁的解决办法

    大家好,我是木瓜太香.大家在开发单页应用的时候,经常会遇到这样的需求,头部和尾部两个组件是大多数组件公用的,而中间的内容区域则是单独存在的,而且一般内容组件逻辑会比较多,如果我们不停刷新页面可能会出现 ...

随机推荐

  1. Python常用的数据类型转换

    在实际开发中.经常要根据需求来转变一些变量的类型. 需要用到以下函数:

  2. MacBook Pro维修过程

    上个月买了2016款无touchbar的MacBook Pro,这款的键盘跟15年版本的很不一样. 在用了三周左右,就发现有个键按着不灵活了,像是进了水一样,黏住感觉,必须要大力按才会出来.思来想去, ...

  3. Cassandra联手Spark 大数据分析将迎来哪些改变?

    2014Spark峰会在美国旧金山举行,与会数据库平台供应商DataStax宣布,与Spark供应商Databricks合作,在它的旗舰产 品 DataStax Enterprise 4.5 (DSE ...

  4. nginx配置tomcat负载均衡,nginx.conf配置文件的配置

  5. SpringMVC handleMapping映射过程

    初始化IOC容器 Spring初始化的时候会优先初始化自定义的类,下面这个就是 org.springframework.web.servlet.mvc.method.annotation.Reques ...

  6. [MCM] 多目标优化 MOP(multi-objective programming)

    生活中许多问题都是由相互冲突和影响的多个目标组成.人们会经常遇到使多个目标在给定区域同时尽可能最佳的优化问题,也就是多目标优化问题.优化问题存在的优化目标超过一个并需要同时处理就成为多目标优化问题. ...

  7. 【vue】vue +element 搭建项目,组件之间通信

    父子组件通信 父 通过props属性给 子传递数据 子 操作 父  this.$parent.XXX 子通过$emit传递参数 或者通过vue-bus vue-bus既可以实现父子组件之间的通信,也可 ...

  8. 005_解决pip国外安装源慢的问题

    用默认的pip安装源pypi.python.org由于在国外经常会出现超时的问题,而且安装速度极其的慢,如下图中的超时问题=>

  9. WiFi-ESP8266入门http(2-2)文件系统-复杂结构的网页 + 文本框交互WIFI信息

    网友教程:https://blog.csdn.net/solar_Lan/article/details/74231360 通过网友教程,我们搭建了文件系统.在此基础上,我们增加WIFI交互. 现有功 ...

  10. JS上传文件、导入文件

    //开始导入 function Import() { var filepath = $('#txtUpload').val(); //校验是否选择表格 if (filepath == '') { $( ...