2010-06-24 92 views

回答

10

我明白了。發生這種情況是因爲TabControl通過要求父控件在自己的窗口中繪製自己而部分地繪製自己。必要的,因爲選項卡不覆蓋控制的全部寬度,他們「伸出」。如果BackgroundImage繪製速度慢,則會在所繪製的背景與在其上繪製的選項卡之間看到閃爍。

這將很難解決,TabControl不支持任何類型的雙緩衝。您只能通過使BackgroundImage高效繪製來最大限度地降低效果。您需要通過使圖像與面板的ClientSize的大小完全一致來實現,以便圖像不必調整大小。並用PixelFormat32bppPArgb像素格式創建該位圖,通常比其他圖像快10倍。

有一種魔法治療可用,windows有一個樣式標誌,可以爲整個窗口(包括其子控件)啓用雙緩衝。自XP以來支持,但一些副作用已被報告。這段代碼粘貼到您的形式,它修復了TabControl的閃爍:

protected override CreateParams CreateParams { 
     get { 
      CreateParams cp = base.CreateParams; 
      cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED 
      return cp; 
     } 
    } 

但要注意的是,視覺風格渲染的TabControl有這種風格的一個標誌,而主要的不兼容。如果你的標籤溢出,你得到的選擇箭頭,然後它去香蕉,並開始渲染標籤一遍又一遍,產生非常高的閃爍率。

+0

這樣做的竅門,謝謝! – jwarzech 2010-06-24 18:19:17

+0

忘記標記答案爲答案,這解決了我的問題,謝謝:0) – jwarzech 2010-06-25 19:09:15

+0

真棒,拯救了我的一天! – BerggreenDK 2012-01-06 12:57:07

-1

您可以嘗試創建一個使用雙緩衝的面板。從面板派生並設置DoubleBuffered爲true:

public partial class DoubleBufferedPanel : Panel 
    { 
     public DoubleBufferedPanel() 
     { 
     InitializeComponent(); 

     this.DoubleBuffered = true; 

     UpdateStyles(); 
     } 
    } 
0

我已經試過溶液的CreateParams,並介紹了自己的問題。我需要動態地添加和刪除選項卡,並且在刪除選項卡後,即使在Invalidate()方法之後,帶WS_EX_COMPOSITED的TabControl也不會自我重繪。只有當我將鼠標移動到選項卡區域時,TabControl纔會開始以非常奇怪的方式重繪自己。

所以最後我來到了這個解決方案:

public class TabControlX : TabControl 
{ 
    protected override void WndProc(ref Message m) 
    { 
     if(m.Msg == WinAPI.WM_MOUSEMOVE && !HotTrack) 
      return; 

     base.WndProc(ref m); 
    } 
} 

public const int WM_MOUSEMOVE = 0x0200; 

對於一些未知的原因HotTrack財產TabControl控件不工作,所以我其實已經固定它:)

當然,它在調整大小時不起作用,但它對我很好。

0

感謝來自Hans Passant的多個答案,我能夠創建一個只有在需要時纔會處於該模式的切換版本,在這種情況下:當選項卡控件由於父窗體而調整大小時。

這並不容易,因爲我決定最好讓它聽取表單的大小調整開始並調整大小的結尾......這就是我所做的,它適合我的需求,tabcontrol不再閃爍從窗體調整大小正在調整大小。

public class NoFlickerTabControl : TabControl 
{ 
    #region PInvoke Change Window Rendering Style Params 

    public static IntPtr SetWindowLong(HandleRef hWnd, int nIndex, IntPtr dwNewLong) 
    { 
     if (IntPtr.Size == 8) 
     { 
      return SetWindowLongPtr64(hWnd, nIndex, dwNewLong); 
     } 
     else 
     { 
      return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong.ToInt32())); 
     } 
    } 

    [DllImport("user32.dll", EntryPoint = "SetWindowLong")] 
    private static extern int SetWindowLong32(HandleRef hWnd, int nIndex, int dwNewLong); 

    [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")] 
    private static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, IntPtr dwNewLong); 

    public enum WindowLongFlags : int 
    { 
     GWL_WNDPROC = -4, 
     GWL_HINSTANCE = -6, 
     GWL_HWNDPARENT = -8, 
     GWL_STYLE = -16, 
     GWL_EXSTYLE = -20, 
     GWL_USERDATA = -21, 
     GWL_ID = -12 
    } 

    #endregion 

    #region Tab Control Style! 

    public NoFlickerTabControl() 
    { 
     SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true); 
    } 

    #region Events to use from Parent 

    private bool bNeedToLinkFormResizeEvents = true; 

    private void ParentForm_ResizeBegin(object sender, EventArgs e) 
    { 
     EnableWS_EX_COMPOSITED(); 
    } 

    private void ParentForm_ResizeEnd(object sender, EventArgs e) 
    { 
     DisableWS_EX_COMPOSITED(); 
    } 

    #endregion 

    #region Enable/Disabled WS_EX_COMPOSITED 

    private const int WS_EX_COMPOSITED = 0x02000000; 

    private void EnableWS_EX_COMPOSITED() 
    { 
     CreateParams cp = CreateParams; 
     cp.ExStyle |= WS_EX_COMPOSITED; // Turn on WS_EX_COMPOSITED 
     //Make our call. 
     HandleRef handleRef = new HandleRef(null, Handle); 
     IntPtr style = new IntPtr(cp.ExStyle); 
     SetWindowLong(handleRef, (int)WindowLongFlags.GWL_EXSTYLE, style); 
    } 

    private void DisableWS_EX_COMPOSITED() 
    { 
     CreateParams cp = CreateParams; 
     cp.ExStyle &= ~WS_EX_COMPOSITED; // Turn OFF WS_EX_COMPOSITED (in case it's been set) 
     //Make our call. 
     HandleRef handleRef = new HandleRef(null, Handle); 
     IntPtr style = new IntPtr(cp.ExStyle); 
     SetWindowLong(handleRef, (int)WindowLongFlags.GWL_EXSTYLE, style); 
    } 

    #endregion 

    protected override void WndProc(ref Message m) 
    { 
     int WM_MOUSEMOVE = 0x0200; 
     if (m.Msg == WM_MOUSEMOVE && !HotTrack) 
     { 
      return; 
     } 

     base.WndProc(ref m); 
    } 

    protected override void OnPaint(PaintEventArgs e) 
    { 
     if(Width <= 0 || Height <= 0) 
     { 
      return; 
     } 

     //Paint related, found it was best to do the check here when control finally gets Parent set by the program. 
     if (bNeedToLinkFormResizeEvents) 
     { 
      Form parentForm = FindForm(); 
      if (parentForm != null) 
      { 
       bNeedToLinkFormResizeEvents = false; 
       parentForm.ResizeBegin += ParentForm_ResizeBegin; 
       parentForm.ResizeEnd += ParentForm_ResizeEnd; 
      } 
     } 

     //~~~~~~ DO THE PAINTING OF THE CONTROL NOW. 

    } 

    #endregion 
}