• C#关于TreeView树在节点数较多时总是会出现闪烁的问题方法记录


             首先介绍下背景吧,问题如题,这个问题应该说困扰我大半年了(不是说我没有请教大佬,不是说我没有上网查过,之前在搜索时,总是没有解决此问题~~),直到最近一次在在优化代码时,再次上网查找,在发现搜索词条”C#控件闪烁问题“,才有了下文。额额额,于是我记录了下面得到片段。

             对于TreeView节点可以动态创建,而且数量还很大的时候,我们给其设置什么双缓冲,使用EndUpdate操作啥的,都是没有效果的。使用了下面的代码即可解决问题;

            根据调式,我查找出瓶颈在于每次更新完界面的EndUpdate操作(使用这个是为了减少界面更新次数,但这里不理想是因为控件中中的元素很多),猜想大概每次更新,.Net底层都会更新重绘每个图元,所以速度会慢,造成闪烁。但是如果这样,使用双缓冲应该会有较好效果。再看代码,发现可能是更新动作太过频繁,于是降低速度,有所好转,但还是不行。

           继续在网上查阅,最终找到一个方案比较合适。原来底层重绘每次会清除画布,然后再全部重新绘制,这才是导致闪烁最主要的原因。于是重载消息发送函数操作,禁掉这条消息。代码如下:

            protected override void WndProc(ref Message m)

            {

                if (m.Msg == 0x0014) // 禁掉清除背景消息WM_ERASEBKGND

                    return;

                base.WndProc(ref m);

            }

            成功!

    注意了,注意了,这里其实不只是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)

          {

                   // 此处书写过滤消息代码

          }

          但是实际实验显示无效果,不知是什么原因,没有细究。

    上面转载网友的!仅为记录下。

  • 相关阅读:
    golangWEB框架gin学习之路由群组
    golangWEB框架gin学习之获取post参数
    golangWEB框架gin学习之获取get参数
    golang之bufio包的使用
    linux配置java环境变量
    jmeter接口测试实践
    Selenium2(java)框架设计 九
    Selenium2(java)页面对象模型(Page Object) 八
    Selenium2(java)TestNG的使用 七
    Selenium2(java)selenium常用API 六
  • 原文地址:https://www.cnblogs.com/ysq0908/p/9919080.html
Copyright © 2020-2023  润新知