Imports System Imports System.Collections.Generic Imports System.ComponentModel Imports System.Windows.Forms Imports System.Drawing Public Class Highlighter Inherits Component Private _Highlights As Dictionary(Of Control, eHighlightColor) = New Dictionary(Of Control, eHighlightColor)() Private _HighlightOnFocus As Dictionary(Of Control, Boolean) = New Dictionary(Of Control, Boolean)() Protected Overrides Sub Dispose(ByVal disposing As Boolean) If _ContainerControl IsNot Nothing Then RemoveHandler _ContainerControl.SizeChanged, AddressOf ContainerControlSizeChanged RemoveHandler _ContainerControl.HandleCreated, AddressOf ContainerControlHandleCreated End If If _HighlightPanel IsNot Nothing AndAlso _HighlightPanel.Parent Is Nothing AndAlso Not _HighlightPanel.IsDisposed Then _HighlightPanel.Dispose() _HighlightPanel = Nothing Else _HighlightPanel = Nothing End If MyBase.Dispose(disposing) End Sub Public Function GetHighlightOnFocus(ByVal c As Control) As Boolean If _HighlightOnFocus.ContainsKey(c) Then Return _HighlightOnFocus(c) End If Return False End Function Public Sub SetHighlightOnFocus(ByVal c As Control, ByVal highlight As Boolean) If c Is Nothing Then Throw New NullReferenceException() If _HighlightOnFocus.ContainsKey(c) Then If Not highlight Then RemoveHighlightOnFocus(_HighlightOnFocus, c) End If Return End If If highlight Then AddHighlightOnFocus(_HighlightOnFocus, c) End Sub Private Sub AddHighlightOnFocus(ByVal highlightOnFocus As Dictionary(Of Control, Boolean), ByVal c As Control) AddHandler c.Enter, AddressOf ControlHighlightEnter AddHandler c.Leave, AddressOf ControlHighlightLeave AddHandler c.VisibleChanged, AddressOf ControlHighlightVisibleChanged highlightOnFocus.Add(c, True) End Sub Private Sub ControlHighlightVisibleChanged(ByVal sender As Object, ByVal e As EventArgs) If _HighlightPanel IsNot Nothing AndAlso _HighlightPanel.FocusHighlightControl = sender Then UpdateHighlighterRegion() End Sub Private Sub ControlHighlightLeave(ByVal sender As Object, ByVal e As EventArgs) If _HighlightPanel IsNot Nothing Then _HighlightPanel.FocusHighlightControl = Nothing UpdateHighlighterRegion() End Sub Private Sub ControlHighlightEnter(ByVal sender As Object, ByVal e As EventArgs) If _HighlightPanel IsNot Nothing Then If Not _HighlightPanel.Visible Then _HighlightPanel.Visible = True _HighlightPanel.BringToFront() _HighlightPanel.FocusHighlightControl = CType(sender, Control) End If UpdateHighlighterRegion() End Sub Private Sub RemoveHighlightOnFocus(ByVal highlightOnFocus As Dictionary(Of Control, Boolean), ByVal c As Control) RemoveHandler c.Enter, AddressOf ControlHighlightEnter RemoveHandler c.Leave, AddressOf ControlHighlightLeave RemoveHandler c.VisibleChanged, AddressOf ControlHighlightVisibleChanged highlightOnFocus.Remove(c) End Sub Public Function GetHighlightColor(ByVal c As Control) As eHighlightColor If _Highlights.ContainsKey(c) Then Return _Highlights(c) End If Return eHighlightColor.None End Function Public Sub SetHighlightColor(ByVal c As Control, ByVal highlightColor As eHighlightColor) If _Highlights.ContainsKey(c) Then If highlightColor = eHighlightColor.None Then RemoveHighlight(_Highlights, c) Else Dim color As eHighlightColor = _Highlights(c) RemoveHighlight(_Highlights, c) AddHighlight(_Highlights, c, highlightColor) End If ElseIf highlightColor <> eHighlightColor.None Then AddHighlight(_Highlights, c, highlightColor) End If End Sub Private _TabControl2 As Dictionary(Of System.Windows.Forms.TabControl, Integer) = New Dictionary(Of System.Windows.Forms.TabControl, Integer)() Private _ParentPanel As Dictionary(Of Panel, Integer) = New Dictionary(Of Panel, Integer)() Private Sub AddHighlight(ByVal highlights As Dictionary(Of Control, eHighlightColor), ByVal c As Control, ByVal highlightColor As eHighlightColor) highlights.Add(c, highlightColor) AddHandler c.LocationChanged, New EventHandler(AddressOf ControlLocationChanged) AddHandler c.SizeChanged, New EventHandler(AddressOf ControlSizeChanged) AddHandler c.VisibleChanged, New EventHandler(AddressOf ControlVisibleChanged) If _HighlightPanel IsNot Nothing Then If Not _HighlightPanel.Visible Then _HighlightPanel.Visible = True _HighlightPanel.BringToFront() End If If c.Parent Is Nothing Then AddHandler c.ParentChanged, AddressOf ControlParentChanged Else AddTabControlHandlers(c) End If UpdateHighlighterRegion() End Sub Private Sub ControlParentChanged(ByVal sender As Object, ByVal e As EventArgs) Dim c As Control = CType(sender, Control) RemoveHandler c.ParentChanged, AddressOf ControlParentChanged AddTabControlHandlers(c) End Sub Private Sub AddTabControlHandlers(ByVal c As Control) Dim tab2 As System.Windows.Forms.TabControl = TryCast(GetParentControl(c, GetType(System.Windows.Forms.TabControl)), System.Windows.Forms.TabControl) If tab2 IsNot Nothing Then If _TabControl2.ContainsKey(tab2) Then _TabControl2(tab2) = _TabControl2(tab2) + 1 Else _TabControl2.Add(tab2, 1) AddHandler tab2.SelectedIndexChanged, AddressOf WinFormsTabSelectedIndexChanged End If Else Dim parentPanel As Panel = TryCast(GetParentControl(c, GetType(Panel)), Panel) If parentPanel IsNot Nothing Then If _ParentPanel.ContainsKey(parentPanel) Then _ParentPanel(parentPanel) = _ParentPanel(parentPanel) + 1 Else _ParentPanel.Add(parentPanel, 1) AddHandler parentPanel.Resize, AddressOf ParentPanelResized AddHandler parentPanel.LocationChanged, AddressOf ParentPanelLocationChanged End If End If End If End Sub Private Sub ParentPanelLocationChanged(ByVal sender As Object, ByVal e As EventArgs) UpdateHighlights() End Sub Private Sub ParentPanelResized(ByVal sender As Object, ByVal e As EventArgs) UpdateHighlights() End Sub Private Sub WinFormsTabSelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) UpdateHighlighterRegion() End Sub Private Function GetParentControl(ByVal c As Control, ByVal parentType As Type) As Control Dim parent As Control = c.Parent While parent IsNot Nothing If parentType.IsAssignableFrom(parent.[GetType]()) Then Return parent parent = parent.Parent End While Return Nothing End Function Private Sub ControlVisibleChanged(ByVal sender As Object, ByVal e As EventArgs) UpdateHighlighterRegion() End Sub Private Sub ControlSizeChanged(ByVal sender As Object, ByVal e As EventArgs) UpdateHighlighterRegion() End Sub Private Sub ControlLocationChanged(ByVal sender As Object, ByVal e As EventArgs) UpdateHighlighterRegion() End Sub Private Sub UpdateHighlighterRegion() If _HighlightPanel IsNot Nothing Then _HighlightPanel.UpdateRegion() End Sub Public Sub UpdateHighlights() UpdateHighlighterRegion() End Sub Private Sub RemoveHighlight(ByVal highlights As Dictionary(Of Control, eHighlightColor), ByVal c As Control) highlights.Remove(c) RemoveHandler c.LocationChanged, New EventHandler(AddressOf ControlLocationChanged) RemoveHandler c.SizeChanged, New EventHandler(AddressOf ControlSizeChanged) RemoveHandler c.VisibleChanged, New EventHandler(AddressOf ControlVisibleChanged) Dim tab2 As System.Windows.Forms.TabControl = TryCast(GetParentControl(c, GetType(System.Windows.Forms.TabControl)), System.Windows.Forms.TabControl) If tab2 IsNot Nothing Then If _TabControl2.ContainsKey(tab2) Then If _TabControl2(tab2) = 1 Then _TabControl2.Remove(tab2) RemoveHandler tab2.SelectedIndexChanged, AddressOf WinFormsTabSelectedIndexChanged Else _TabControl2(tab2) = _TabControl2(tab2) - 1 End If End If Else Dim parentPanel As Panel = TryCast(GetParentControl(c, GetType(Panel)), Panel) If parentPanel IsNot Nothing Then If _ParentPanel.ContainsKey(parentPanel) Then If _ParentPanel(parentPanel) = 1 Then _ParentPanel.Remove(parentPanel) RemoveHandler parentPanel.LocationChanged, AddressOf ParentPanelLocationChanged RemoveHandler parentPanel.SizeChanged, AddressOf ParentPanelResized Else _ParentPanel(parentPanel) = _ParentPanel(parentPanel) - 1 End If End If End If End If UpdateHighlighterRegion() End Sub Friend ReadOnly Property Highlights As Dictionary(Of Control, eHighlightColor) Get Return _Highlights End Get End Property Private _FocusHighlightColor As eHighlightColor = eHighlightColor.Blue Public Property FocusHighlightColor As eHighlightColor Get Return _FocusHighlightColor End Get Set(ByVal value As eHighlightColor) _FocusHighlightColor = value If _HighlightPanel IsNot Nothing Then _HighlightPanel.FocusHighlightColor = value UpdateHighlighterRegion() End If End Set End Property Private _HighlightPanel As HighlightPanel = Nothing Private _ContainerControl As Control = Nothing Public Property ContainerControl As Control Get Return _ContainerControl End Get Set(ByVal value As Control) If Me.DesignMode Then _ContainerControl = value Return End If If _ContainerControl IsNot value Then If _ContainerControl IsNot Nothing Then RemoveHandler _ContainerControl.SizeChanged, AddressOf ContainerControlSizeChanged RemoveHandler _ContainerControl.HandleCreated, AddressOf ContainerControlHandleCreated If _HighlightPanel IsNot Nothing AndAlso _HighlightPanel.Parent Is _ContainerControl Then _ContainerControl.Controls.Remove(_HighlightPanel) End If _ContainerControl = value If _ContainerControl IsNot Nothing Then If _HighlightPanel Is Nothing Then _HighlightPanel = New HighlightPanel(_Highlights) _HighlightPanel.FocusHighlightColor = _FocusHighlightColor _HighlightPanel.Margin = New System.Windows.Forms.Padding(0) _HighlightPanel.Padding = New System.Windows.Forms.Padding(0) _HighlightPanel.CustomHighlightColors = _CustomHighlightColors _HighlightPanel.Visible = False End If AddHandler _ContainerControl.SizeChanged, AddressOf ContainerControlSizeChanged AddHandler _ContainerControl.HandleCreated, AddressOf ContainerControlHandleCreated _ContainerControl.Controls.Add(_HighlightPanel) UpdateHighlightPanelBounds() End If End If End Set End Property Private Sub ContainerControlHandleCreated(ByVal sender As Object, ByVal e As EventArgs) If _Highlights.Count > 0 AndAlso _HighlightPanel IsNot Nothing AndAlso Not _HighlightPanel.Visible Then _HighlightPanel.Visible = True End Sub Private Sub UpdateHighlightPanelBounds() Dim bounds As Rectangle = New Rectangle(0, 0, _ContainerControl.ClientRectangle.Width, _ContainerControl.ClientRectangle.Height) If TypeOf _HighlightPanel.Parent Is Form Then Dim form As Form = TryCast(_HighlightPanel.Parent, Form) If form.AutoSize Then bounds.X += form.Padding.Left bounds.Y += form.Padding.Top bounds.Width -= form.Padding.Horizontal bounds.Height -= form.Padding.Vertical End If End If If _HighlightPanel.Bounds.Equals(bounds) Then _HighlightPanel.UpdateRegion() Else _HighlightPanel.Bounds = bounds End If _HighlightPanel.BringToFront() End Sub Private _DelayTimer As Timer = Nothing Private Sub ContainerControlSizeChanged(ByVal sender As Object, ByVal e As EventArgs) Dim form As Form = TryCast(sender, Form) If form IsNot Nothing Then If _DelayTimer Is Nothing Then _DelayTimer = New Timer() _DelayTimer.Interval = 100 AddHandler _DelayTimer.Tick, New EventHandler(AddressOf DelayTimerTick) _DelayTimer.Start() End If Return End If UpdateHighlightPanelBounds() End Sub Private Sub DelayTimerTick(ByVal sender As Object, ByVal e As EventArgs) Dim timer As Timer = _DelayTimer _DelayTimer = Nothing RemoveHandler timer.Tick, New EventHandler(AddressOf DelayTimerTick) timer.[Stop]() timer.Dispose() UpdateHighlightPanelBounds() End Sub Private _CustomHighlightColors As Color() = Nothing Public Property CustomHighlightColors As Color() Get Return _CustomHighlightColors End Get Set(ByVal value As Color()) _CustomHighlightColors = value If _HighlightPanel IsNot Nothing Then _HighlightPanel.CustomHighlightColors = _CustomHighlightColors _HighlightPanel.Invalidate() End If End Set End Property Public Function CanExtend(ByVal extendee As Object) As Boolean Return (TypeOf extendee Is Control) End Function Private Sub SetError(ByVal control As Control, ByVal value As String) Me.SetHighlightColor(control, eHighlightColor.Red) End Sub Private Sub ClearError(ByVal control As Control) Me.SetHighlightColor(control, eHighlightColor.None) End Sub End Class Public Enum eHighlightColor None Red Blue Green Orange Custom End Enum