1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
| Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Reflection
Public Class TabControlEX
Inherits System.Windows.Forms.TabControl
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
SetStyle(ControlStyles.AllPaintingInWmPaint Or _
ControlStyles.DoubleBuffer Or _
ControlStyles.ResizeRedraw Or _
ControlStyles.UserPaint, True)
End Sub
'UserControl1 overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
components = New System.ComponentModel.Container
End Sub
#End Region
#Region " InterOP "
<StructLayout(LayoutKind.Sequential)> _
Private Structure NMHDR
Public HWND As Int32
Public idFrom As Int32
Public code As Int32
Public Overloads Function ToString() As String
Return String.Format("Hwnd: {0}, ControlID: {1}, Code: {2}", HWND, idFrom, code)
End Function
End Structure
Private Const TCN_FIRST As Int32 = &HFFFFFFFFFFFFFDDA&
Private Const TCN_SELCHANGING As Int32 = (TCN_FIRST - 2)
Private Const WM_USER As Int32 = &H400&
Private Const WM_NOTIFY As Int32 = &H4E&
Private Const WM_REFLECT As Int32 = WM_USER + &H1C00&
#End Region
#Region " BackColor Manipulation "
'As well as exposing the property to the Designer we want it to behave just like any other
'controls BackColor property so we need some clever manipulation.
Private m_Backcolor As Color = Color.Empty
<Browsable(True), _
Description("The background color used to display text and graphics in a control.")> _
Public Overrides Property BackColor() As Color
Get
If m_Backcolor.Equals(Color.Empty) Then
If Parent Is Nothing Then
Return Control.DefaultBackColor
Else
Return Parent.BackColor
End If
End If
Return m_Backcolor
End Get
Set(ByVal Value As Color)
If m_Backcolor.Equals(Value) Then Return
m_Backcolor = Value
Invalidate()
'Let the Tabpages know that the backcolor has changed.
MyBase.OnBackColorChanged(EventArgs.Empty)
End Set
End Property
Public Function ShouldSerializeBackColor() As Boolean
Return Not m_Backcolor.Equals(Color.Empty)
End Function
Public Overrides Sub ResetBackColor()
m_Backcolor = Color.Empty
Invalidate()
End Sub
#End Region
Protected Overrides Sub OnParentBackColorChanged(ByVal e As System.EventArgs)
MyBase.OnParentBackColorChanged(e)
Invalidate()
End Sub
Protected Overrides Sub OnSelectedIndexChanged(ByVal e As System.EventArgs)
MyBase.OnSelectedIndexChanged(e)
Invalidate()
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
e.Graphics.Clear(BackColor)
Dim r As Rectangle = Me.ClientRectangle
If TabCount <= 0 Then Return
'Draw a custom background for Transparent TabPages
r = SelectedTab.Bounds
Dim sf As New StringFormat
sf.Alignment = StringAlignment.Center
sf.LineAlignment = StringAlignment.Center
Dim DrawFont As New Font(Font.FontFamily, 24, FontStyle.Regular, GraphicsUnit.Pixel)
ControlPaint.DrawStringDisabled(e.Graphics, "Micks Ownerdraw TabControl", DrawFont, BackColor, RectangleF.op_Implicit(r), sf)
DrawFont.Dispose()
'Draw a border around TabPage
r.Inflate(3, 3)
Dim tp As TabPage = TabPages(SelectedIndex)
Dim PaintBrush As New SolidBrush(tp.BackColor)
e.Graphics.FillRectangle(PaintBrush, r)
'ControlPaint.DrawBorder(e.Graphics, r, PaintBrush.Color, ButtonBorderStyle.Solid)
ControlPaint.DrawBorder(e.Graphics, r, PaintBrush.Color, ButtonBorderStyle.Dotted)
'Draw the Tabs
For index As Integer = 0 To TabCount - 1
tp = TabPages(index)
r = GetTabRect(index)
'Dim bs As ButtonBorderStyle = ButtonBorderStyle.Outset
Dim bs As ButtonBorderStyle = ButtonBorderStyle.Inset
If index = SelectedIndex Then bs = ButtonBorderStyle.None
PaintBrush.Color = tp.BackColor
e.Graphics.FillRectangle(PaintBrush, r)
'=====================================================================
ControlPaint.DrawBorder(e.Graphics, r, PaintBrush.Color, bs)
'=====================================================================
PaintBrush.Color = tp.ForeColor
'Set up rotation for left and right aligned tabs
If Alignment = TabAlignment.Left Or Alignment = TabAlignment.Right Then
Dim RotateAngle As Single = 90
If Alignment = TabAlignment.Left Then RotateAngle = 270
Dim cp As New PointF(r.Left + (r.Width \ 2), r.Top + (r.Height \ 2))
e.Graphics.TranslateTransform(cp.X, cp.Y)
e.Graphics.RotateTransform(RotateAngle)
r = New Rectangle(-(r.Height \ 2), -(r.Width \ 2), r.Height, r.Width)
End If
'Draw the Tab Text
If tp.Enabled Then
e.Graphics.DrawString(tp.Text, Font, PaintBrush, RectangleF.op_Implicit(r), sf)
Else
ControlPaint.DrawStringDisabled(e.Graphics, tp.Text, Font, tp.BackColor, RectangleF.op_Implicit(r), sf)
End If
e.Graphics.ResetTransform()
Next
PaintBrush.Dispose()
End Sub
<Description("Occurs as a tab is being changed.")> _
Public Event SelectedIndexChanging As SelectedTabPageChangeEventHandler
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = (WM_REFLECT + WM_NOTIFY) Then
Dim hdr As NMHDR = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(NMHDR)), NMHDR)
If hdr.code = TCN_SELCHANGING Then
Dim tp As TabPage = TestTab(Me.PointToClient(Windows.Forms.Cursor.Position))
If Not tp Is Nothing Then
Dim e As New TabPageChangeEventArgs(Me.SelectedTab, tp)
RaiseEvent SelectedIndexChanging(Me, e)
If e.Cancel OrElse tp.Enabled = False Then
m.Result = New IntPtr(1)
Return
End If
End If
End If
End If
MyBase.WndProc(m)
End Sub
Private Function TestTab(ByVal pt As Point) As TabPage
For index As Integer = 0 To TabCount - 1
If GetTabRect(index).Contains(pt.X, pt.Y) Then
Return TabPages(index)
End If
Next
Return Nothing
End Function
End Class
#Region " EventArgs Class's "
Public Class TabPageChangeEventArgs
Inherits EventArgs
Private _Selected As TabPage
Private _PreSelected As TabPage
Public Cancel As Boolean = False
Public ReadOnly Property CurrentTab() As TabPage
Get
Return _Selected
End Get
End Property
Public ReadOnly Property NextTab() As TabPage
Get
Return _PreSelected
End Get
End Property
Public Sub New(ByVal CurrentTab As TabPage, ByVal NextTab As TabPage)
_Selected = CurrentTab
_PreSelected = NextTab
End Sub
End Class
Public Delegate Sub SelectedTabPageChangeEventHandler(ByVal sender As Object, ByVal e As TabPageChangeEventArgs)
#End Region |
Partager