Movable Tabs on Tabcontrol

Visual Studio 2013 VB.NET

I have a tab control on a windows form (vb.net) that i would like to allow users to change the order by dragging. Is this possible?
mickeyshelley1Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Jacques Bourgeois (James Burger)PresidentCommented:
The TabPage the necessary method (DoDragDrop) and events (DragDrop), so it is possible.

Unfortunately, I do not have any code to show you. I never did it, and it can involve quite a few lines.

Look at the documentation for the DoDragDrop method, that shows the whole thing on both sides (start the drag and control the drop) between 2 ListBoxes. You would need something similar to insert a TabPage between 2 other TabPages.
0
Mike EghtebasDatabase and Application DeveloperCommented:
tabs
I made this tab control, with two tabs. Then with mouse down, I dragged left or right. and then I let it go:

 mouse down used to capture the initial x value using:
Public Class Form1

    Dim Xinitial As Int32
    Dim Xfinal As Int32

    Private Sub TabPage2_MouseClick(sender As Object, e As MouseEventArgs) Handles TabPage2.MouseClick
        Xinitial = e.X
    End Sub

let it go helped to find final value of x:
    Private Sub TabPage2_MouseUp(sender As Object, e As MouseEventArgs) Handles TabPage2.MouseUp
        Xfinal = e.X

       'determined the user dragged to left or right:
        If Xfinal > Xfinal Then
            changeTabIndex("TabPage2", 1) ' to the right
        Else
            changeTabIndex("TabPage2", -1) ' to the left
        End If

    End Sub

This function could be further developed to re-index the refresh the form to rearrange the tabs:
    Private Sub changeTabIndex(TabName As String, intVal As Int32)
        Dim intNewIndex As Int32

       ' intNewIndex = TabControl1.SelectedIndex + intVal

        'TabControl1.SelectedIndex = intNewIndex

    End Sub

End Class

This is what I have done so far. I stopped to search if there is easier way of doing this so I don't have to re-invent the wheel.

Please the mouse-down and up on the tab area will respond to these events. They will not respond to if you work on tab on the top row.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ArkCommented:
Public Class DraggableTabControl
    Inherits TabControl

    Private _srcPage As TabPage

    Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
        If (e.Button = MouseButtons.Left) AndAlso (SelectedTab IsNot Nothing) AndAlso (Not GetTabRect(SelectedIndex).IsEmpty) Then
            _srcPage = SelectedTab
        End If
        MyBase.OnMouseDown(e)
    End Sub

    Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
        If (e.Button = MouseButtons.Left) AndAlso (_srcPage IsNot Nothing) Then
            Me.Cursor = If(TabPageFromPoint(e.Location) Is Nothing, Cursors.No, Cursors.VSplit)
        Else
            Me.Cursor = Cursors.Default
        End If
        MyBase.OnMouseMove(e)
    End Sub

    Protected Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)
        SwapPages(_srcPage, TabPageFromPoint(e.Location))
        Me.SelectedTab = _srcPage
        _srcPage = Nothing
        MyBase.Cursor = Cursors.Default
        MyBase.OnMouseUp(e)
    End Sub

    Private Function TabPageFromPoint(ByVal pt As Point) As TabPage
        For i As Integer = 0 To TabPages.Count - 1
            If GetTabRect(i).Contains(pt) Then Return TabPages(i)
        Next
        Return Nothing
    End Function

    Private Sub SwapPages(ByVal a As TabPage, ByVal b As TabPage)
        If a Is Nothing OrElse b Is Nothing OrElse a.Equals(b) Then Return
        Dim i = TabPages.IndexOf(a), j = TabPages.IndexOf(b)
        TabPages(i) = b : TabPages(j) = a
    End Sub
End Class

Open in new window

0
ArkCommented:
PS. Another approach - using drag'n'drop:
Public Class DraggableTabControl
    Inherits TabControl

    Public Sub New()
        MyBase.New()
        MyBase.AllowDrop = True
    End Sub
    Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
        If (e.Button = MouseButtons.Left) AndAlso (SelectedTab IsNot Nothing) AndAlso (Not GetTabRect(SelectedIndex).IsEmpty) Then
            DoDragDrop(SelectedTab, DragDropEffects.All)
        End If
        MyBase.OnMouseDown(e)
    End Sub

    Private Sub DraggableTabControl_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Me.DragDrop
        If e.Data.GetDataPresent(GetType(TabPage)) Then
            Dim target = TabPageFromPoint(Me.PointToClient(New Point(e.X, e.Y)))
            Dim srcPage = e.Data.GetData(GetType(TabPage))
            SwapPages(srcPage, target)
            Me.SelectedTab = srcPage
        End If
    End Sub

    Private Sub DraggableTabControl_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Me.DragOver
        If e.Data.GetDataPresent(GetType(TabPage)) Then
            Dim target = TabPageFromPoint(Me.PointToClient(New Point(e.X, e.Y)))
            Dim srcPage = e.Data.GetData(GetType(TabPage))
            If target Is Nothing OrElse target.Equals(srcPage) Then
                e.Effect = DragDropEffects.None
            Else
                e.Effect = DragDropEffects.Move
            End If
        End If
    End Sub

    Private Function TabPageFromPoint(ByVal pt As Point) As TabPage
        For i As Integer = 0 To MyBase.TabPages.Count - 1
            If GetTabRect(i).Contains(pt) Then Return TabPages(i)
        Next
        Return Nothing
    End Function

    Private Sub SwapPages(ByVal a As TabPage, ByVal b As TabPage)
        If a Is Nothing OrElse b Is Nothing OrElse a.Equals(b) Then Return
        Dim i = TabPages.IndexOf(a), j = TabPages.IndexOf(b)
        TabPages(i) = b : TabPages(j) = a
    End Sub

End Class

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.