您現在的位置: 365建站網 > 365學習 > 解決C#/vb.net winform中的panel重繪導致界面閃爍問題

解決C#/vb.net winform中的panel重繪導致界面閃爍問題

文章來源:365jz.com     點擊數:2636    更新時間:2018-06-22 21:07   參與評論

首先我們需要重新創建一個Panel類,其繼承系統自帶的Panel類,然后充新寫一個構造函數,對其中的部分樣式進行更改。

代碼:


public class NewPanel:Panel  
{  
    public NewPanel()  
    {  
        this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);  
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);  
        this.SetStyle(ControlStyles.UserPaint, true);  
    }  
}

  


然后在窗口初始化的代碼塊中更改為我們當前新建的Panel類即可,其它代碼都不必用~。

個人認為是非常棒的一種解決方案,可以完全解決閃爍的問題。


利用winform開發時,可能都會遇到一個問題,就是在panel中不停的重繪圖形時,圖形會不停的閃爍。要解決這個辦法只需要開啟雙緩沖即可,由于初學c#,理解的不是很深,所以不多做解釋。以下代碼親測可以解決這個問題:

首先創建一個自己的panel類:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Windows.Forms;  
   
namespace Test  
{  
    //開啟雙緩沖  
    class MyPanel:Panel  
    {  
        public MyPanel()  
        {  
            SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor, true);  
        }  
    }  
}

  


然后重新生成解決方法,就會發現工具箱中多了一個自己寫的panel控件,在畫圖形的時候,畫在自己的panel上就可以了。由于自己的panel繼承自Panel類,所以Panel中的方法都可以使用。


vb.net版本:

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Namespace Test
    
    '開啟雙緩沖   
    Class MyPanel
        Inherits Panel
        
        Public Sub New()
            MyBase.New
            SetStyle((ControlStyles.UserPaint  _
                            Or (ControlStyles.AllPaintingInWmPaint  _
                            Or (ControlStyles.OptimizedDoubleBuffer  _
                            Or (ControlStyles.ResizeRedraw Or ControlStyles.SupportsTransparentBackColor)))), true)
        End Sub
    End Class
End Namespace


另外技術文章說明:


一、通過對窗體和控件使用雙緩沖來減少圖形閃爍(當繪制圖片時出現閃爍時,使用雙緩沖)

對于大多數應用程序,.NET Framework 提供的默認雙緩沖將提供最佳效果。默認情況下,標準 Windows 窗體控件是雙緩沖的??梢酝ㄟ^兩種方法對窗體和所創作的控件啟用默認雙緩沖。一種方法是將 DoubleBuffered 屬性設置為 true,另一種方法是通過調用 SetStyle 方法將 OptimizedDoubleBuffer 標志設置為 true。兩種方法都將為窗體或控件啟用默認雙緩沖并提供無閃爍的圖形呈現。建議僅對已為其編寫所有呈現代碼的自定義控件調用 SetStyle 方法。

在構造函數里加上以下代碼:

this.DoubleBuffered = true;//設置本窗體
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
SetStyle(ControlStyles.DoubleBuffer, true); // 雙緩沖
//SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
//UpdateStyles();

 

二、C#控件的閃爍問題解決方法總結
最近對代碼作了一些優化,試驗后效果還可以,但是發現界面會閃爍,具體是TreeView控件會閃爍,語言為C#,IDE為VS2005。在查閱一些資料,使用了一些基本技術后(如開啟雙緩沖),發現沒什么效果。
        于是使用Profiler工具,查找出瓶頸在于每次更新完界面的EndUpdate操作(使用這個是為了減少界面更新次數,但這里不理想是因為控件中中的元素很多),猜想大概每次更新,.Net底層都會更新重繪每個圖元,所以速度會慢,造成閃爍。但是如果這樣,使用雙緩沖應該會有較好效果。再看代碼,發現可能是更新動作太過頻繁,于是降低速度,有所好轉,但還是不行。
       繼續在網上查閱,最終找到一個方案比較合適。原來底層重繪每次會清除畫布,然后再全部重新繪制,這才是導致閃爍最主要的原因。于是重載消息發送函數操作,禁掉這條消息。代碼如下:

protected override void WndProc(ref Message m)
 {
     if (m.Msg == 0x0014) // 禁掉清除背景消息
        return;
     base.WndProc(ref m);
 }

  

成功!

 

注:雙緩沖還是有用的,在更新不是很頻繁且控件內含元素不是特別多的時候。一旦元素過多,每次更新時間都比較長,即便使用了雙緩沖,仍解決不了閃爍問題。個人認為最終比較理想的方法還是禁掉清除背景消息。


附:一些嘗試過但失敗的記錄
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)
      {
               // 此處書寫過濾消息代碼
      }
      但是實際實驗顯示無效果,不知是什么原因,沒有細究。

 

三、個人在一個winfrom中測試利用timer控件對要刷新的控件進行定時刷新,可能也能起到作用。

 

四、C# winform 局部刷新
做winform界面程序時,經常會遇到后臺處理占用大量時間的情況,這就會造成界面假死狀態。一般解決界面假死有兩種方式:要么把占用大量時間的處理方式放入其他線程;要么把界面顯示放入其他線程。第一種方式應該比較簡單,開單獨的線程,處理數據,將處理數據顯示到界面就好。但是我們經常需要在主程序運算一些內容,否則可能會改動比較大。因此,這里講講第二種方式。
同樣是使用多線程,但是c#在其他線程刷新有一點點問題,即不能跨線程操作界面。這可以使用控件的Invoke方法解決:

private delegate void CrossThread();
 Control control = ....;
 CrossThread cross = delegate()
 {
      control.Refresh();
 };
 control.Invoke(cross);

這樣可以讓控件在其它線程刷新界面。


再加上開新線程后的通用方法:

 private void InvaliateControl(Control control)
  {
      Thread t = new Thread(
          new ThreadStart(delegate()
          {
              CrossThread cross = delegate()
              {
                  control.Refresh();
              };
             control.Invoke(cross);
         }
     ));
 }

這樣就可以在任何時候,調用此方法對控件進行刷新,而不將整個界面刷新。如果對于同一個控件,連續多次刷新,可以添加一個成員變量作為標記,以免同一控件連續多次刷新,提升部分性能。


補充:在主線程調用耗時操作用此方法可能會有問題,經過驗證調用Invoke函數,其實是在主線程刷新界面。



如對本文有疑問,請提交到交流論壇,廣大熱心網友會為你解答??! 點擊進入論壇


發表評論 (2636人查看,0條評論)
請自覺遵守互聯網相關的政策法規,嚴禁發布色情、暴力、反動的言論。
用戶名: 驗證碼: 點擊我更換圖片
最新評論
------分隔線----------------------------
自拍偷拍福力视频,偷拍国际精品,麻豆一区福利电影,国产网红视频午夜福利,se视频大全,久久国产AV影院 >jav HD tubevideo| 97国产婷婷综合在线视频| 色欲色欲日韩www在线观看| 高清成年美女黄网站色大全| 韩国无码av片| 日本邪恶少女漫画| 欧美人与动牲交视频| 国产精品欧美亚洲韩国日本久久| 从小开始淫乱的生活| 大陆精大陆国产国语精品| 麻豆剧果冻传媒在线播放| 亚洲jizzjizz在线播放| 18japanese宾馆直播| 久久精品伊人一区二区三区| 人人弄狠狠婷五月丁香| 国产欧美亚洲精品第1页| 欧美乱码伦视频免费| 狠狠色噜噜狠狠狠狠色综合久| 色婷婷五月综合激情中文字幕| 内裤太透明毛都露出来了大全| 香港三级a∨在线观看| 14一16学生毛片视频| 壮志高飞电视剧全集在线观看| 尤物网| 成本人h无码播放私人影院| 极品人妻互换| 调教家政妇| 电影一本道AV免费高清| 两性男女交_配现场视频| 杨幂真紧好爽全文阅读| 小sao货水好多真紧| http://www.edogstar.com