· Adhiere el Form a los bordes de la pantalla al mover la ventana cerca de los bordes.
Ejemplo de uso:
Código
Private WindowSticker As New WindowSticker(ClientForm:=Me) With {.SnapMargin = 35}
Código
' *********************************************************************** ' Author : Elektro ' Last Modified On : 09-19-2014 ' *********************************************************************** ' <copyright file="WindowSticker.vb" company="Elektro Studios"> ' Copyright (c) Elektro Studios. All rights reserved. ' </copyright> ' *********************************************************************** #Region " Usage Examples " ' Private WindowSticker As New WindowSticker(ClientForm:=Me) With {.SnapMargin = 35} 'Private Sub Form1_Load() Handles MyBase.Shown ' WindowSticker.Dispose() ' WindowSticker = New WindowSticker(Form2) ' WindowSticker.ClientForm.Show() 'End Sub #End Region #Region " Imports " Imports System.ComponentModel Imports System.Runtime.InteropServices #End Region #Region " WindowSticker " ''' <summary> ''' Sticks a Form to a Desktop border (if the Form is near). ''' </summary> Public Class WindowSticker : Inherits NativeWindow : Implements IDisposable #Region " Properties " #Region " Public " ''' <summary> ''' Gets the client form used to stick its borders. ''' </summary> ''' <value>The client form used to stick its borders.</value> Public ReadOnly Property ClientForm As Form Get Return Me._ClientForm End Get End Property Private WithEvents _ClientForm As Form = Nothing ''' <summary> ''' Gets or sets the snap margin (offset), in pixels. ''' (Default value is: 30)) ''' </summary> ''' <value>The snap margin (offset), in pixels.</value> Public Property SnapMargin As Integer Get Return Me._SnapMargin End Get Set(ByVal value As Integer) Me.DisposedCheck() Me._SnapMargin = value End Set End Property Private _SnapMargin As Integer = 30I #End Region #Region " Private " ''' <summary> ''' Gets rectangle that contains the size of the current screen. ''' </summary> ''' <value>The rectangle that contains the size of the current screen.</value> Private ReadOnly Property ScreenRect As Rectangle Get Return Screen.FromControl(Me._ClientForm).Bounds End Get End Property ''' <summary> ''' Gets the working area of the current screen. ''' </summary> ''' <value>The working area of the current screen.</value> Private ReadOnly Property WorkingArea As Rectangle Get Return Screen.FromControl(Me._ClientForm).WorkingArea End Get End Property ''' <summary> ''' Gets the desktop taskbar height (when thet taskbar is horizontal). ''' </summary> ''' <value>The desktop taskbar height (when thet taskbar is horizontal).</value> Private ReadOnly Property TaskbarHeight As Integer Get Return Me.ScreenRect.Height - Me.WorkingArea.Height End Get End Property #End Region #End Region #Region " Enumerations " ''' <summary> ''' Windows Message Identifiers. ''' </summary> <Description("Messages to process in WndProc")> Public Enum WindowsMessages As Integer ''' <summary> ''' Sent to a window whose size, position, or place in the Z order is about to change. ''' MSDN Documentation: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632653%28v=vs.85%29.aspx ''' </summary> WM_WINDOWPOSCHANGING = &H46I End Enum #End Region #Region " Structures " ''' <summary> ''' Contains information about the size and position of a window. ''' MSDN Documentation: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632612%28v=vs.85%29.aspx ''' </summary> <StructLayout(LayoutKind.Sequential)> Public Structure WINDOWPOS ''' <summary> ''' A handle to the window. ''' </summary> Public hwnd As IntPtr ''' <summary> ''' The position of the window in Z order (front-to-back position). ''' This member can be a handle to the window behind which this window is placed, ''' or can be one of the special values listed with the 'SetWindowPos' function. ''' </summary> Public hwndInsertAfter As IntPtr ''' <summary> ''' The position of the left edge of the window. ''' </summary> Public x As Integer ''' <summary> ''' The position of the top edge of the window. ''' </summary> Public y As Integer ''' <summary> ''' The window width, in pixels. ''' </summary> Public width As Integer ''' <summary> ''' The window height, in pixels. ''' </summary> Public height As Integer ''' <summary> ''' Flag containing the window position. ''' </summary> Public flags As Integer End Structure #End Region #Region " Constructor " ''' <summary> ''' Initializes a new instance of WindowSticker class. ''' </summary> ''' <param name="ClientForm">The client form to assign this NativeWindow.</param> Public Sub New(ByVal ClientForm As Form) ' Assign the Formulary. Me._ClientForm = ClientForm End Sub ''' <summary> ''' Prevents a default instance of the <see cref="WindowSticker"/> class from being created. ''' </summary> Private Sub New() 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 _ClientForm.HandleCreated, _ClientForm.Load, _ClientForm.Shown If (Me._ClientForm IsNot Nothing) AndAlso (Not MyBase.Handle.Equals(Me._ClientForm.Handle)) Then MyBase.AssignHandle(Me._ClientForm.Handle) End If End Sub ''' <summary> ''' Releases the Handle. ''' </summary> Private Sub OnHandleDestroyed() Handles _ClientForm.HandleDestroyed MyBase.ReleaseHandle() End Sub #End Region #Region " WndProc " ''' <summary> ''' Invokes the default window procedure associated with this window to process messages. ''' </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) If (Me._ClientForm IsNot Nothing) AndAlso (m.Msg = WindowsMessages.WM_WINDOWPOSCHANGING) Then Me.SnapToDesktopBorder(ClientForm:=Me._ClientForm, Handle:=m.LParam, widthAdjustment:=0) End If MyBase.WndProc(m) End Sub #End Region #Region " Private Methods " ''' <summary> ''' Sticks a Form to a desktop border (it its near). ''' </summary> ''' <param name="ClientForm">The client form used to stick its borders.</param> ''' <param name="Handle">A pointer to a 'WINDOWPOS' structure that contains information about the window's new size and position.</param> ''' <param name="widthAdjustment">The border width adjustment.</param> Private Sub SnapToDesktopBorder(ByVal ClientForm As Form, ByVal Handle As IntPtr, Optional ByVal widthAdjustment As Integer = 0I) Dim newPosition As WINDOWPOS = CType(Marshal.PtrToStructure(Handle, GetType(WINDOWPOS)), WINDOWPOS) If (newPosition.y = 0) OrElse (newPosition.x = 0) Then ' Nothing to do. Exit Sub End If ' Top border (check if taskbar is on top or bottom via WorkingRect.Y) If (newPosition.y >= -SnapMargin AndAlso (Me.WorkingArea.Y > 0 AndAlso newPosition.y <= (Me.TaskbarHeight + Me.SnapMargin))) _ OrElse (Me.WorkingArea.Y <= 0 AndAlso newPosition.y <= (SnapMargin)) Then If Me.TaskbarHeight > 0 Then ' Horizontal Taskbar newPosition.y = Me.WorkingArea.Y Else ' Vertical Taskbar newPosition.y = 0 End If End If ' Left border If (newPosition.x >= Me.WorkingArea.X - Me.SnapMargin) _ AndAlso (newPosition.x <= Me.WorkingArea.X + Me.SnapMargin) Then newPosition.x = Me.WorkingArea.X End If ' Right border. If (newPosition.x + Me._ClientForm.Width <= Me.WorkingArea.Right + Me.SnapMargin) _ AndAlso (newPosition.x + Me._ClientForm.Width >= Me.WorkingArea.Right - Me.SnapMargin) Then newPosition.x = (Me.WorkingArea.Right - Me._ClientForm.Width) End If ' Bottom border. If (newPosition.y + Me._ClientForm.Height <= Me.WorkingArea.Bottom + Me.SnapMargin) _ AndAlso (newPosition.y + Me._ClientForm.Height >= Me.WorkingArea.Bottom - Me.SnapMargin) Then newPosition.y = (Me.WorkingArea.Bottom - Me._ClientForm.Height) End If ' Marshal it back. Marshal.StructureToPtr([structure]:=newPosition, ptr:=Handle, fDeleteOld:=True) End Sub #End Region #Region " Hidden Methods " ''' <summary> ''' Determines whether the specified System.Object instances are the same instance. ''' </summary> <EditorBrowsable(EditorBrowsableState.Never)> Private Shadows Sub ReferenceEquals() End Sub ''' <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> ''' Destroys the window and its handle. ''' </summary> <EditorBrowsable(EditorBrowsableState.Never)> Public Shadows Sub DestroyHandle() End Sub ''' <summary> ''' Releases the handle associated with this window. ''' </summary> <EditorBrowsable(EditorBrowsableState.Never)> Public Shadows Sub ReleaseHandle() End Sub ''' <summary> ''' Retrieves the window associated with the specified handle. ''' </summary> <EditorBrowsable(EditorBrowsableState.Never)> Private Shadows Sub FromHandle() End Sub ''' <summary> ''' Serves as a hash function for a particular type. ''' </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 Function GetLifeTimeService() Return Nothing End Function ''' <summary> ''' Obtains a lifetime service object to control the lifetime policy for this instance. ''' </summary> <EditorBrowsable(EditorBrowsableState.Never)> Public Shadows Function InitializeLifeTimeService() Return Nothing End Function ''' <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 Function CreateObjRef() Return Nothing End Function ''' <summary> ''' Determines whether the specified System.Object instances are considered equal. ''' </summary> <EditorBrowsable(EditorBrowsableState.Never)> Public Shadows Sub Equals() End Sub ''' <summary> ''' Returns a String that represents the current object. ''' </summary> <EditorBrowsable(EditorBrowsableState.Never)> Public Shadows Sub ToString() End Sub ''' <summary> ''' Invokes the default window procedure associated with this window. ''' </summary> <EditorBrowsable(EditorBrowsableState.Never)> Public Shadows Sub DefWndProc() End Sub #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._ClientForm = Nothing MyBase.ReleaseHandle() MyBase.DestroyHandle() End If End If Me.IsDisposed = True End Sub #End Region End Class #End Region