Ciao
Dato che il framework non ti mette a disposizione un evento "Moving", devi eseguire l'override della funzione WndProc e gestire il messaggio WM_MOVING da lì. In questo modo puoi modificare il rettangolo della finestra prima che sia spostata, mantenendola nello schermo.
Eccoti un esempio di codice:
Public Class TuaForm
Private Const WM_MOVING As Integer = &H216
<StructLayout(LayoutKind.Sequential)> _
Private Structure RECT
Public left As Integer
Public top As Integer
Public right As Integer
Public bottom As Integer
Public Sub New(ByVal rect As Rectangle)
Me.left = rect.Left
Me.right = rect.Right
Me.top = rect.Top
Me.bottom = rect.Bottom
End Sub
Public Function ToRectangle() As Rectangle
Return Rectangle.FromLTRB(left, top, right, bottom)
End Function
End Structure
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_MOVING Then
' Ottiene la nuova posizione del controllo
Dim rect As Rectangle = m.GetLParam(GetType(RECT)).ToRectangle()
' Ottiene le coordinate dello schermo
Dim scr As Rectangle = Screen.GetWorkingArea(Me)
' Se il controllo supera lo schermo, lo rimette all'interno
If Not scr.Contains(rect) Then
' Ottiene l'intersezione fra schermo e finestra
Dim intersect As Rectangle = Rectangle.Intersect(rect, scr)
' Ottiene l'offset dell'asse x e y per riportare il controllo nello schermo
Dim x As Integer = IIf(rect.Left < 0, -rect.Left, intersect.Right - rect.Right)
Dim y As Integer = IIf(rect.Top < 0, -rect.Top, intersect.Bottom - rect.Bottom)
' Esegue l'offset, riportando il controllo nello schermo
rect.Offset(x, y)
' Imposta il nuovo rettangolo della finestra
Marshal.StructureToPtr(New RECT(rect), m.LParam, False)
End If
' Avvisa che il messaggio è stato processato
m.Result = True
Else
' Chiama il gestore predefinito
MyBase.WndProc(m)
End If
End Sub
End Class
Luca