【VB.NET】带关闭按钮的选项卡

'来源:http://www.vbforums.com/showthread.php?622242-TabControl-with-Close-button-on-TabPages-(with-Design-Time-support)

Option Strict On
Imports System.ComponentModel



<ToolboxBitmap(GetType(System.Windows.Forms.TabControl))>
Public Class TabControlEx
    Inherits System.Windows.Forms.TabControl

    Private Declare Auto Function SetParent Lib "user32" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
    Protected CloseButtonCollection As New Dictionary(Of Button, TabPage)
    Private _ShowCloseButtonOnCurrentTab As Boolean = True
    Private _ShowCloseButtonOnTabs As Boolean = False


    <Browsable(True), DefaultValue(True), Category("Behavior"), Description("Indicates whether a close button should be shown on each TabPage")>
    Public Property ShowCloseButtonOnCurrentTab() As Boolean
        Get
            Return _ShowCloseButtonOnCurrentTab
        End Get
        Set(ByVal value As Boolean)
            _ShowCloseButtonOnCurrentTab = value
            For Each btn In CloseButtonCollection.Keys
                btn.Visible = _ShowCloseButtonOnCurrentTab
            Next
            RePositionCloseButtons()
        End Set
    End Property


    <Browsable(True), DefaultValue(True), Category("Behavior"), Description("Indicates whether a close button should be shown on each TabPage")>
    Public Property ShowCloseButtonOnTabs() As Boolean
        Get
            Return _ShowCloseButtonOnTabs
        End Get
        Set(ByVal value As Boolean)
            _ShowCloseButtonOnTabs = value

            RePositionCloseButtons()
        End Set
    End Property

    Protected Overrides Sub OnCreateControl()
        MyBase.OnCreateControl()


        For Each item In CloseButtonCollection
            item.Value.Text = item.Value.Text.Trim & Space(4)
        Next

        RePositionCloseButtons()
    End Sub

    Protected Overrides Sub OnControlAdded(ByVal e As System.Windows.Forms.ControlEventArgs)
        MyBase.OnControlAdded(e)
        Dim tp As TabPage = DirectCast(e.Control, TabPage)
        Dim rect As Rectangle = Me.GetTabRect(Me.TabPages.IndexOf(tp))
        Dim btn As Button = AddCloseButton(tp)
        btn.Size = New Size(rect.Height - 1, rect.Height - 1)
        btn.Location = New Point(rect.X + rect.Width - rect.Height - 1, rect.Y + 1)
        SetParent(btn.Handle, Me.Handle)
        AddHandler btn.Click, AddressOf OnCloseButtonClick
        CloseButtonCollection.Add(btn, tp)
    End Sub

    Protected Overrides Sub OnControlRemoved(ByVal e As System.Windows.Forms.ControlEventArgs)
        Dim btn As Button = CloseButtonOfTabPage(DirectCast(e.Control, TabPage))
        RemoveHandler btn.Click, AddressOf OnCloseButtonClick
        CloseButtonCollection.Remove(btn)
        SetParent(btn.Handle, Nothing)
        btn.Dispose()
        MyBase.OnControlRemoved(e)
    End Sub

    Protected Overrides Sub OnLayout(ByVal levent As System.Windows.Forms.LayoutEventArgs)
        MyBase.OnLayout(levent)
        RePositionCloseButtons()
    End Sub

    Public Event CloseButtonClick As CancelEventHandler
    Protected Overridable Sub OnCloseButtonClick(ByVal sender As Object, ByVal e As EventArgs)
        If Not DesignMode Then
            Dim btn As Button = DirectCast(sender, Button)
            Dim tp As TabPage = CloseButtonCollection(btn)
            Dim ee As New CancelEventArgs
            RaiseEvent CloseButtonClick(sender, ee)

            If Not ee.Cancel Then
                If MsgBox("是否关闭 " + tp.Text.Trim + "标签?") = MsgBoxResult.Ok Then
                    Me.TabPages.Remove(tp)
                    RePositionCloseButtons()
                End If
            End If
            End If
    End Sub

    Protected Overridable Function AddCloseButton(ByVal tp As TabPage) As Button
        Dim closeButton As New Button
        With closeButton
            '' TODO: Give a good visual appearance to the Close button, maybe by assigning images etc.
            ''       Here I have not used images to keep things simple.
            .Text = "X"
            .FlatStyle = FlatStyle.Flat
            .BackColor = Color.FromKnownColor(KnownColor.ButtonFace)
            .ForeColor = Color.White
            .Font = New Font("Microsoft Sans Serif", 6, FontStyle.Bold)
        End With
        Return closeButton
    End Function

    Public Sub RePositionCloseButtons()
        For Each item In CloseButtonCollection
            RePositionCloseButtons(item.Value)
        Next
    End Sub

    Public Sub RePositionCloseButtons(ByVal tp As TabPage)
        Dim btn As Button = CloseButtonOfTabPage(tp)
        If btn IsNot Nothing Then
            Dim tpIndex As Integer = Me.TabPages.IndexOf(tp)
            If tpIndex >= 0 Then
                Dim rect As Rectangle = Me.GetTabRect(tpIndex)
                If Me.SelectedTab Is tp Then
                    btn.BackColor = Color.Red
                    btn.Size = New Size(rect.Height - 1, rect.Height - 1)
                    btn.Location = New Point(rect.X + rect.Width - rect.Height, rect.Y + 1)
                    btn.Visible = ShowCloseButtonOnCurrentTab
                Else
                    btn.BackColor = Color.FromKnownColor(KnownColor.ButtonFace)
                    btn.Size = New Size(rect.Height - 3, rect.Height - 3)
                    btn.Location = New Point(rect.X + rect.Width - rect.Height - 1, rect.Y + 1)
                    btn.Visible = Me.ShowCloseButtonOnTabs
                End If

                btn.BringToFront()
            End If
        End If
    End Sub

    Protected Function CloseButtonOfTabPage(ByVal tp As TabPage) As Button
        Return (From item In CloseButtonCollection Where item.Value Is tp Select item.Key).FirstOrDefault
    End Function
End Class

 

发表回复