首先介绍下背景吧,问题如题,这个问题应该说困扰我大半年了(不是说我没有请教大佬,不是说我没有上网查过,以前在搜索时,老是没有解决此问题~~),直到最近一次在在优化代码时,再次上网查找,在发现搜索词条”C#控件闪烁问题“,才有了下文。额额额,因而我记录了下面获得片断。程序员
对于TreeView节点能够动态建立,并且数量还很大的时候,咱们给其设置什么双缓冲,使用EndUpdate操做啥的,都是没有效果的。使用了下面的代码便可解决问题;ide
根据调式,我查找出瓶颈在于每次更新完界面的EndUpdate操做(使用这个是为了减小界面更新次数,但这里不理想是由于控件中中的元素不少),猜测大概每次更新,.Net底层都会更新重绘每一个图元,因此速度会慢,形成闪烁。可是若是这样,使用双缓冲应该会有较好效果。再看代码,发现多是更新动做太过频繁,因而下降速度,有所好转,但仍是不行。函数
继续在网上查阅,最终找到一个方案比较合适。原来底层重绘每次会清除画布,而后再所有从新绘制,这才是致使闪烁最主要的缘由。因而重载消息发送函数操做,禁掉这条消息。代码以下:优化
protected override void WndProc(ref Message m)spa
{.net
if (m.Msg == 0x0014) // 禁掉清除背景消息WM_ERASEBKGND视频
return;blog
base.WndProc(ref m);继承
}get
成功!
注意了,注意了,这里其实不仅是TreeView控件有闪烁问题,在C#中只要控件的内容数量大,都会存在闪烁。产生闪烁缘由以下:
Windows在窗口的具体绘制以前,会发送WM_ERASEBKGND消息通知该窗口檫除背景。默认状况下,会以窗口的默认背景色清除窗口。
WM_ERASEBKGND消息和WM_PAINT消息的另一种含义:背景色与前景色
能够这样理解WM_ERASEBKGND消息和WM_PAINT消息:
1.WM_ERASEBKGND消息用于通知系统或者程序员绘制背景色
2.WM_PAINT消息用于通知程序员绘制前景色,好比在WM_PAINT中调用TextOut函数输出文本
详情能够看看这位网友的:https://blog.csdn.net/analogous_love/article/details/50039467
注:双缓冲仍是有用的,在更新不是很频繁且控件内含元素不是特别多的时候。一旦元素过多,每次更新时间都比较长,即使使用了双缓冲,仍解决不了闪烁问题。我的认为最终比较理想的方法仍是禁掉清除背景消息。
附:一些尝试过但失败的记录(下面的方法我没有尝试)
1)使用setStyle
网上有说使用setStyle函数去设置该控件的参数,具体为:
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
这三个选项参数后者是依赖前者的,必须并存,不然无效。而且这个函数自己是protected的,因此首先须要继承某控件再使用。
这个目标是跟前面正确解决方案一致,也是禁止清除背景并开启双缓冲,但须要使用用户绘制选项,并且是所有交由用户绘制。这须要本身实现控件的所有绘制,比较麻烦。因此这个方法不是彻底不可行,可是须要额外工做量,不推荐。我也没有使用。
2)使用BeginUpdate和EndUpdate(这个尝试过,没效果)
这一对操做对于须要批量操做更新控件的情景有比较好的效果,好比初始化时批量添加了大量节点。坏处就在于不能即时更新。因此,对于频繁的更新节点并但愿当即反映到界面的状况不适用。若是使用而且没有禁掉清除界面消息的话,则控件看起来就会不停的闪烁,并且以白底为主,内容几乎不可见(这个视频繁程度而定)。由于界面更新都在EndUpdate处完成,操做太多致使EndUpdate阻塞时间过长,且清空在先,更新在后,致使界面看起来长时间处于空白状态。
3)使用ControlStyles.EnableNotifyMessage选项
这个选项的做用和正确解决方案也是一致的。使用方法是:
SetStyle(ControlStyles.EnableNotifyMessage, true);
protected override void onNotifyMessage(Message m)
{
// 此处书写过滤消息代码
}
可是实际实验显示无效果,不知是什么缘由,没有细究。
上面转载网友的!仅为记录下。