TabControl blinks when image is background

I noticed that if I have a TabControl in the panel with the background of the image, when the mouse is over the tab, it blinks and redraws. Is there any workaround to prevent this from happening?

+3
source share
4 answers

I see it. This is because TabControl is partially distracted by asking the parent control to draw itself inside its own window. This is necessary because the tabs do not cover the entire width of the control; they stick out. If the BackgroundImage is slowly drawing, you will see a flicker between the background image and the tabs drawn on top of it.

, TabControl . , BackgroundImage . , ClientSize, . PixelFormat32bppPArgb, 10 , .

, , , . XP, . , TabControl:

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

, TabControl . , , , .

+10

CreateParams, . , TabControl WS_EX_COMPOSITED Invalidate(). , 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

, , , , , : - .

, , , ... , , , 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 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
}
0

, . DoubleBuffered true:

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

         this.DoubleBuffered = true;

         UpdateStyles();
      }
   }
-1

Source: https://habr.com/ru/post/1751614/


All Articles