Search code examples
c#winformsdrag-and-droptabcontroltabpage

TabPage title alignment being wrong after drag'n'dropping


I have the class that extends System.Windows.Forms.TabControl and had implemented drag'n'drop mechanism for its TabPages as following:

#region Overriden base methods

protected override void OnDragOver(DragEventArgs e)
{
    if (PointedTabPage == null) return;

    e.Effect = DragDropEffects.Move;

    var dragTab = e.Data.GetData(typeof (ManagedTabPage)) as ManagedTabPage;

    if (dragTab == null) return;

    int dropIndex = TabPages.IndexOf(PointedTabPage);
    int dragIndex = TabPages.IndexOf(dragTab);

    if (dragIndex == dropIndex) return;

    var modifiedTabPages = new List<ManagedTabPage>(from ManagedTabPage tabPage in TabPages
                                                    where TabPages.IndexOf(tabPage) != dragIndex
                                                    select TabPages[TabPages.IndexOf(tabPage)] as ManagedTabPage);

    modifiedTabPages.Insert(dropIndex, dragTab);

    for (byte i = 0; i < TabPages.Count; ++i)
    {
        var managedTabPage = TabPages[i] as ManagedTabPage;

        if (managedTabPage != null && managedTabPage.Uid == modifiedTabPages[i].Uid)
            continue;

        TabPages[i] = modifiedTabPages[i];
    }

    SelectedTab = dragTab;
}

protected override void OnMouseDown(MouseEventArgs e)
{
    try
    {
        switch (e.Button)
        {
            case MouseButtons.Left:
                DoDragDrop(PointedTabPage, DragDropEffects.Move);

                break;
            case MouseButtons.Middle:
                CloseTab(PointedTabPage);

                break;
        }
    }
    catch (InvalidOperationException)
    {
    }
    finally
    {
        TabPages.Insert(0, String.Empty);
        TabPages.RemoveAt(0);
    }
}

#endregion

Nota bene that in the finally clause of OnMouseDown method there are 2 lines for workarounding the
problem: for some reason w/o these lines after drag'n'dropping any of TabPages alignment of their titles is being wrong: draganddrop

What should I do to correct this behavior without this smelly workaround? Maybe sending some Windows messages could do the trick? Thanks a lot for any suggestions.

Edit 1. Code of ManagedTabPage is 100% unimportant (it's just extends TabPage with some specific properties).

PointedTabPage is unimportant too, but this is it:

return (from ManagedTabPage tabPage in TabPages
        let tabPageIndex = TabPages.IndexOf(tabPage)
        where GetTabRect(tabPageIndex).Contains(PointToClient(Cursor.Position))
        select TabPages[tabPageIndex]).Single() as ManagedTabPage;

I'm trying to achieve fully-centered alignment of labels. You see, labels on the screenshot didn't centered horizontally?


Solution

  • since you hasn't shared ManagedTabPage code, i used default TabPage control

    changes are made in method OnDragOver

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace Demo
    {
        public class MyTabControl : TabControl
        {
            public MyTabControl()
            {
                SizeMode = TabSizeMode.Fixed; 
                ItemSize = new Size(224, 20);
            }
    
            #region Overriden base methods
    
            protected override void OnDragOver(DragEventArgs e)
            {
                if (DesignMode)
                    return;
                if (PointedTabPage == null) return;
    
                e.Effect = DragDropEffects.Move;
    
                var dragTab = e.Data.GetData(typeof(TabPage)) as TabPage;
    
                if (dragTab == null) return;
    
                int dropIndex = TabPages.IndexOf(PointedTabPage);
                int dragIndex = TabPages.IndexOf(dragTab);
    
                if (dragIndex == dropIndex) return;
    
                // change position of tab
                TabPages.Remove(dragTab);
                TabPages.Insert(dropIndex, dragTab);
    
                SelectedTab = dragTab;
    
                base.OnDragOver(e);
            }
    
            protected override void OnMouseDown(MouseEventArgs e)
            {
                if (DesignMode)
                    return;
    
                switch (e.Button)
                {
                    case MouseButtons.Left:
                        DoDragDrop(PointedTabPage, DragDropEffects.Move);                    
    
                        break;
                    case MouseButtons.Middle:
                        TabPages.Remove(PointedTabPage);
                        break;
                }
            }
    
            #endregion
    
            TabPage PointedTabPage
            {
                get
                {
                    return TabPages.OfType<TabPage>()
                        .Where((p, tabPageIndex) => GetTabRect(tabPageIndex).Contains(PointToClient(Cursor.Position)))
                        .FirstOrDefault();
                }
            }
        }
    }