' ***********************************************************************
' Author : Elektro
' Created : 01-12-2014
' Modified : 01-12-2014
' ***********************************************************************
' <copyright file="FormBorderManager.vb" company="Elektro Studios">
' Copyright (c) Elektro Studios. All rights reserved.
' </copyright>
' ***********************************************************************
#Region " Usage Examples "
'Public Class Form1
' ' Disable resizing on all border edges.
' Private FormBorders As New FormBorderManager(Me) With
' {
' .Edges = New FormBorderManager.FormEdges With
' {
' .Top = FormBorderManager.WindowHitTestRegions.TitleBar,
' .Left = FormBorderManager.WindowHitTestRegions.TitleBar,
' .Right = FormBorderManager.WindowHitTestRegions.TitleBar,
' .Bottom = FormBorderManager.WindowHitTestRegions.TitleBar,
' .TopLeft = FormBorderManager.WindowHitTestRegions.TitleBar,
' .TopRight = FormBorderManager.WindowHitTestRegions.TitleBar,
' .BottomLeft = FormBorderManager.WindowHitTestRegions.TitleBar,
' .BottomRight = FormBorderManager.WindowHitTestRegions.TitleBar
' }
' }
' Private Shadows Sub Load(sender As Object, e As EventArgs) Handles MyBase.Load
' ' Disables the moving on all border edges.
' FormBorders.SetAllEdgesToNonMoveable()
' End Sub
'End Class
#End Region
#Region " Imports "
Imports System.ComponentModel
#End Region
#Region " FormBorderManager "
''' <summary>
''' Class FormBorderManager.
''' Manages each Form border to indicate their Hit-Region.
''' </summary>
<Description("Manages each Form border to indicate their Hit-Region")>
Friend NotInheritable Class FormBorderManager : Inherits NativeWindow : Implements IDisposable
#Region " Members "
#Region " Miscellaneous "
''' <summary>
''' The form to manage their borders.
''' </summary>
Private WithEvents form As Form = Nothing
#End Region
#Region " Properties "
''' <summary>
''' Gets or sets the Hit-Region of the edges.
''' </summary>
''' <value>The Form edges.</value>
Public Property Edges As New FormEdges
''' <summary>
''' The Edges of the Form.
''' </summary>
Partial Public NotInheritable Class FormEdges
''' <summary>
''' Gets or sets the Hit-Region of the Top form border.
''' </summary>
Public Property Top As WindowHitTestRegions = WindowHitTestRegions.TopSizeableBorder
''' <summary>
''' Gets or sets the Hit-Region of the Left form border.
''' </summary>
Public Property Left As WindowHitTestRegions = WindowHitTestRegions.LeftSizeableBorder
''' <summary>
''' Gets or sets the Hit-Region of the Right form border.
''' </summary>
Public Property Right As WindowHitTestRegions = WindowHitTestRegions.RightSizeableBorder
''' <summary>
''' Gets or sets the Hit-Region of the Bottom form border.
''' </summary>
Public Property Bottom As WindowHitTestRegions = WindowHitTestRegions.BottomSizeableBorder
''' <summary>
''' Gets or sets the Hit-Region of the Top-Left form border.
''' </summary>
Public Property TopLeft As WindowHitTestRegions = WindowHitTestRegions.TopLeftSizeableCorner
''' <summary>
''' Gets or sets the Hit-Region of the Top-Right form border.
''' </summary>
Public Property TopRight As WindowHitTestRegions = WindowHitTestRegions.TopRightSizeableCorner
''' <summary>
''' Gets or sets the Hit-Region of the Bottom-Left form border.
''' </summary>
Public Property BottomLeft As WindowHitTestRegions = WindowHitTestRegions.BottomLeftSizeableCorner
''' <summary>
''' Gets or sets the Hit-Region of the Bottom-Right form border.
''' </summary>
Public Property BottomRight As WindowHitTestRegions = WindowHitTestRegions.BottomRightSizeableCorner
End Class
#End Region
#Region " Enumerations "
''' <summary>
''' Known Windows Message Identifiers.
''' </summary>
<Description("Messages to process in WndProc")>
Private Enum KnownMessages As Integer
''' <summary>
''' Sent to a window in order to determine what part of the window corresponds to a particular screen coordinate.
''' This can happen, for example, when the cursor moves, when a mouse button is pressed or released,
''' or in response to a call to a function such as WindowFromPoint.
''' If the mouse is not captured, the message is sent to the window beneath the cursor.
''' Otherwise, the message is sent to the window that has captured the mouse.
''' <paramref name="WParam" />
''' This parameter is not used.
''' <paramref name="LParam" />
''' The low-order word specifies the x-coordinate of the cursor.
''' The coordinate is relative to the upper-left corner of the screen.
''' The high-order word specifies the y-coordinate of the cursor.
''' The coordinate is relative to the upper-left corner of the screen.
''' </summary>
WM_NCHITTEST = &H84
End Enum
''' <summary>
''' Indicates the position of the cursor hot spot.
''' Options available when a form is tested for mose positions with 'WM_NCHITTEST' message.
''' </summary>
<Description("Return value of the 'WM_NCHITTEST' message")>
Public Enum WindowHitTestRegions
''' <summary>
''' HTERROR: On the screen background or on a dividing line between windows.
''' (same as HTNOWHERE, except that the DefWindowProc function produces a system beep to indicate an error).
''' </summary>
[Error] = -2
''' <summary>
''' HTTRANSPARENT: In a window currently covered by another window in the same thread.
''' (the message will be sent to underlying windows in the same thread
''' until one of them returns a code that is not HTTRANSPARENT).
''' </summary>
TransparentOrCovered = -1
''' <summary>
''' HTNOWHERE: On the screen background or on a dividing line between windows.
''' </summary>
NoWhere = 0
''' <summary>
''' HTCLIENT: In a client area.
''' </summary>
ClientArea = 1
''' <summary>
''' HTCAPTION: In a title bar.
''' </summary>
TitleBar = 2
''' <summary>
''' HTSYSMENU: In a window menu or in a Close button in a child window.
''' </summary>
SystemMenu = 3
''' <summary>
''' HTGROWBOX: In a size box (same as HTSIZE).
''' </summary>
GrowBox = 4
''' <summary>
''' HTMENU: In a menu.
''' </summary>
Menu = 5
''' <summary>
''' HTHSCROLL: In a horizontal scroll bar.
''' </summary>
HorizontalScrollBar = 6
''' <summary>
''' HTVSCROLL: In the vertical scroll bar.
''' </summary>
VerticalScrollBar = 7
''' <summary>
''' HTMINBUTTON: In a Minimize button.
''' </summary>
MinimizeButton = 8
''' <summary>
''' HTMAXBUTTON: In a Maximize button.
''' </summary>
MaximizeButton = 9
''' <summary>
''' HTLEFT: In the left border of a resizable window.
''' (the user can click the mouse to resize the window horizontally).
''' </summary>
LeftSizeableBorder = 10
''' <summary>
''' HTRIGHT: In the right border of a resizable window.
''' (the user can click the mouse to resize the window horizontally).
''' </summary>
RightSizeableBorder = 11
''' <summary>
''' HTTOP: In the upper-horizontal border of a window.
''' </summary>
TopSizeableBorder = 12
''' <summary>
''' HTTOPLEFT: In the upper-left corner of a window border.
''' </summary>
TopLeftSizeableCorner = 13
''' <summary>
''' HTTOPRIGHT: In the upper-right corner of a window border.
''' </summary>
TopRightSizeableCorner = 14
''' <summary>
''' HTBOTTOM: In the lower-horizontal border of a resizable window.
''' (the user can click the mouse to resize the window vertically).
''' </summary>
BottomSizeableBorder = 15
''' <summary>
''' HTBOTTOMLEFT: In the lower-left corner of a border of a resizable window.
''' (the user can click the mouse to resize the window diagonally).
''' </summary>
BottomLeftSizeableCorner = 16
''' <summary>
''' HTBOTTOMRIGHT: In the lower-right corner of a border of a resizable window.
''' (the user can click the mouse to resize the window diagonally).
''' </summary>
BottomRightSizeableCorner = 17
''' <summary>
''' HTBORDER: In the border of a window that does not have a sizing border.
''' </summary>
NonSizableBorder = 18
' ''' <summary>
' ''' HTOBJECT: Not implemented.
' ''' </summary>
' [Object] = 19
''' <summary>
''' HTCLOSE: In a Close button.
''' </summary>
CloseButton = 20
''' <summary>
''' HTHELP: In a Help button.
''' </summary>
HelpButton = 21
''' <summary>
''' HTSIZE: In a size box (same as HTGROWBOX).
''' (Same as GrowBox).
''' </summary>
SizeBox = GrowBox
''' <summary>
''' HTREDUCE: In a Minimize button.
''' (Same as MinimizeButton).
''' </summary>
ReduceButton = MinimizeButton
''' <summary>
''' HTZOOM: In a Maximize button.
''' (Same as MaximizeButton).
''' </summary>
ZoomButton = MaximizeButton
End Enum
#End Region
#End Region
#Region " Constructor "
''' <summary>
''' Initializes a new instance of the <see cref="FormBorderManager"/> class.
''' </summary>
''' <param name="form">The form to assign.</param>
Public Sub New(ByVal form As Form)
' Assign the Formulary.
Me.form = form
End Sub
#End Region
#Region " Event Handlers "
''' <summary>
''' Assign the handle of the target Form to this NativeWindow,
''' necessary to override target Form's WndProc.
''' </summary>
Private Sub SetFormHandle() _
Handles form.HandleCreated, form.Load, form.Shown
If Not MyBase.Handle.Equals(Me.form.Handle) Then
MyBase.AssignHandle(Me.form.Handle)
End If
End Sub
''' <summary>
''' Releases the Handle.
''' </summary>
Private Sub OnHandleDestroyed() _
Handles Form.HandleDestroyed
MyBase.ReleaseHandle()
End Sub
#End Region
#Region " WndProc "
''' <summary>
''' Invokes the default window procedure associated with this window to process messages for this Window.
''' </summary>
''' <param name="m">
''' A <see cref="T:System.Windows.Forms.Message" /> that is associated with the current Windows message.
''' </param>
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
Select Case m.Msg
Case KnownMessages.WM_NCHITTEST
Select Case CType(m.Result, WindowHitTestRegions)
Case WindowHitTestRegions.TopSizeableBorder ' The mouse hotspot is pointing to Top border.
m.Result = New IntPtr(Edges.Top)
Case WindowHitTestRegions.LeftSizeableBorder ' The mouse hotspot is pointing to Left border.
m.Result = New IntPtr(Edges.Left)
Case WindowHitTestRegions.RightSizeableBorder ' The mouse hotspot is pointing to Right border.
m.Result = New IntPtr(Edges.Right)
Case WindowHitTestRegions.BottomSizeableBorder ' The mouse hotspot is pointing to Bottom border.
m.Result = New IntPtr(Edges.Bottom)
Case WindowHitTestRegions.TopLeftSizeableCorner ' The mouse hotspot is pointing to Top-Left border.
m.Result = New IntPtr(Edges.TopLeft)
Case WindowHitTestRegions.TopRightSizeableCorner ' The mouse hotspot is pointing to Top-Right border.
m.Result = New IntPtr(Edges.TopRight)
Case WindowHitTestRegions.BottomLeftSizeableCorner ' The mouse hotspot is pointing to Bottom-Left border.
m.Result = New IntPtr(Edges.BottomLeft)
Case WindowHitTestRegions.BottomRightSizeableCorner ' The mouse hotspot is pointing to Bottom-Right border.
m.Result = New IntPtr(Edges.BottomRight)
End Select
End Select
End Sub
#End Region
#Region " Public Methods "
''' <summary>
''' Disables the resizing on all border edges.
''' </summary>
Public Sub SetAllEdgesToNonResizable()
DisposedCheck()
Me.Edges.Top = WindowHitTestRegions.TitleBar
Me.Edges.Left = WindowHitTestRegions.TitleBar
Me.Edges.Right = WindowHitTestRegions.TitleBar
Me.Edges.Bottom = WindowHitTestRegions.TitleBar
Me.Edges.TopLeft = WindowHitTestRegions.TitleBar
Me.Edges.TopRight = WindowHitTestRegions.TitleBar
Me.Edges.BottomLeft = WindowHitTestRegions.TitleBar
Me.Edges.BottomRight = WindowHitTestRegions.TitleBar
End Sub
''' <summary>
''' Enables the resizing on all border edges.
''' </summary>
Public Sub SetAllEdgesToResizable()
DisposedCheck()
Me.Edges.Top = WindowHitTestRegions.TopSizeableBorder
Me.Edges.Left = WindowHitTestRegions.LeftSizeableBorder
Me.Edges.Right = WindowHitTestRegions.RightSizeableBorder
Me.Edges.Bottom = WindowHitTestRegions.BottomSizeableBorder
Me.Edges.TopLeft = WindowHitTestRegions.TopLeftSizeableCorner
Me.Edges.TopRight = WindowHitTestRegions.TopRightSizeableCorner
Me.Edges.BottomLeft = WindowHitTestRegions.BottomLeftSizeableCorner
Me.Edges.BottomRight = WindowHitTestRegions.BottomRightSizeableCorner
End Sub
''' <summary>
''' Enabled the moving on all border edges.
''' </summary>
Public Sub SetAllEdgesToMoveable()
DisposedCheck()
Me.Edges.Top = WindowHitTestRegions.TopSizeableBorder
Me.Edges.Left = WindowHitTestRegions.LeftSizeableBorder
Me.Edges.Right = WindowHitTestRegions.RightSizeableBorder
Me.Edges.Bottom = WindowHitTestRegions.BottomSizeableBorder
Me.Edges.TopLeft = WindowHitTestRegions.TopLeftSizeableCorner
Me.Edges.TopRight = WindowHitTestRegions.TopRightSizeableCorner
Me.Edges.BottomLeft = WindowHitTestRegions.BottomLeftSizeableCorner
Me.Edges.BottomRight = WindowHitTestRegions.BottomRightSizeableCorner
End Sub
''' <summary>
''' Disables the moving on all border edges.
''' </summary>
Public Sub SetAllEdgesToNonMoveable()
DisposedCheck()
Me.Edges.Top = WindowHitTestRegions.NoWhere
Me.Edges.Left = WindowHitTestRegions.NoWhere
Me.Edges.Right = WindowHitTestRegions.NoWhere
Me.Edges.Bottom = WindowHitTestRegions.NoWhere
Me.Edges.TopLeft = WindowHitTestRegions.NoWhere
Me.Edges.TopRight = WindowHitTestRegions.NoWhere
Me.Edges.BottomLeft = WindowHitTestRegions.NoWhere
Me.Edges.BottomRight = WindowHitTestRegions.NoWhere
End Sub
#End Region
#Region " Hidden methods "
' These methods and properties are purposely hidden from Intellisense just to look better without unneeded methods.
' NOTE: The methods can be re-enabled at any-time if needed.
''' <summary>
''' Assigns a handle to this window.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub AssignHandle()
End Sub
''' <summary>
''' Creates a window and its handle with the specified creation parameters.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub CreateHandle()
End Sub
''' <summary>
''' Creates an object that contains all the relevant information required
''' to generate a proxy used to communicate with a remote object.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub CreateObjRef()
End Sub
''' <summary>
''' Invokes the default window procedure associated with this window.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub DefWndProc()
End Sub
''' <summary>
''' Destroys the window and its handle.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub DestroyHandle()
End Sub
''' <summary>
''' Determines whether the specified object is equal to the current object.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub Equals()
End Sub
''' <summary>
''' Serves as the default hash function.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub GetHashCode()
End Sub
''' <summary>
''' Retrieves the current lifetime service object that controls the lifetime policy for this instance.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub GetLifetimeService()
End Sub
''' <summary>
''' Obtains a lifetime service object to control the lifetime policy for this instance.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub InitializeLifetimeService()
End Sub
''' <summary>
''' Releases the handle associated with this window.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub ReleaseHandle()
End Sub
''' <summary>
''' Gets the handle for this window.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Property Handle()
#End Region
#Region " IDisposable "
''' <summary>
''' To detect redundant calls when disposing.
''' </summary>
Private IsDisposed As Boolean = False
''' <summary>
''' Prevent calls to methods after disposing.
''' </summary>
''' <exception cref="System.ObjectDisposedException"></exception>
Private Sub DisposedCheck()
If Me.IsDisposed Then
Throw New ObjectDisposedException(Me.GetType().FullName)
End If
End Sub
''' <summary>
''' Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
''' </summary>
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
''' <summary>
''' Releases unmanaged and - optionally - managed resources.
''' </summary>
''' <param name="IsDisposing">
''' <c>true</c> to release both managed and unmanaged resources;
''' <c>false</c> to release only unmanaged resources.
''' </param>
Protected Sub Dispose(ByVal IsDisposing As Boolean)
If Not Me.IsDisposed Then
If IsDisposing Then
Me.form = Nothing
MyBase.ReleaseHandle()
MyBase.DestroyHandle()
End If
End If
Me.IsDisposed = True
End Sub
#End Region
End Class
#End Region