Imports System.Drawing Imports System.Windows.Forms Public Class ClassSnapPanel Inherits Panel Private _ShowGrid As Boolean = True Private _GridSize As Integer = 16 Private _NeedsScrollUpdate As Boolean = False Private _SnappingEnabled As Boolean = True ' ← Neu: Snapping deaktivierbar Public Sub New() Me.AutoScroll = True Me.DoubleBuffered = True ' Flackern reduzieren End Sub ''' ''' Deaktiviert das Snapping temporär (z.B. beim Laden von Controls aus der DB) ''' Public Property SnappingEnabled As Boolean Get Return _SnappingEnabled End Get Set(value As Boolean) _SnappingEnabled = value End Set End Property Public Property GridSize As Integer Get Return _GridSize End Get Set(value As Integer) If value > 0 AndAlso value <> _GridSize Then _GridSize = value Invalidate() End If End Set End Property Public Property ShowGrid As Boolean Get Return _ShowGrid End Get Set(value As Boolean) If value <> _ShowGrid Then _ShowGrid = value Invalidate() End If End Set End Property Protected Overrides Sub OnControlAdded(e As ControlEventArgs) MyBase.OnControlAdded(e) ScheduleScrollUpdate() End Sub Protected Overrides Sub OnControlRemoved(e As ControlEventArgs) MyBase.OnControlRemoved(e) ScheduleScrollUpdate() End Sub Protected Overrides Sub OnLayout(levent As LayoutEventArgs) MyBase.OnLayout(levent) ScheduleScrollUpdate() End Sub ''' ''' Snappt ein Control manuell auf das Grid - wird von frmFormDesigner nach einem echten Drag aufgerufen ''' Public Sub SnapControlToGrid(ctrl As Control) If Not _SnappingEnabled OrElse Not _ShowGrid OrElse Me.DesignMode Then Return Dim x As Integer = Math.Floor(ctrl.Left / _GridSize) * _GridSize Dim y As Integer = Math.Floor(ctrl.Top / _GridSize) * _GridSize ctrl.Location = New Point(x, y) ScheduleScrollUpdate() End Sub Protected Overrides Sub OnPaint(e As PaintEventArgs) MyBase.OnPaint(e) If Not Me.DesignMode AndAlso _ShowGrid Then Dim scroll As Point = Me.AutoScrollPosition ' Grid-Ursprung am virtuellen Canvas (0,0) ausrichten ' AutoScrollPosition ist negativ → Modulo ergibt positiven Offset im sichtbaren Bereich Dim offsetX As Integer = ((scroll.X Mod _GridSize) + _GridSize) Mod _GridSize Dim offsetY As Integer = ((scroll.Y Mod _GridSize) + _GridSize) Mod _GridSize ' Rechteck um je eine Rasterzelle vergrößern damit keine Lücken entstehen Dim gridRect As New Rectangle( offsetX - _GridSize, offsetY - _GridSize, Me.ClientSize.Width + _GridSize * 2, Me.ClientSize.Height + _GridSize * 2) ControlPaint.DrawGrid(e.Graphics, gridRect, New Size(_GridSize, _GridSize), Me.BackColor) End If End Sub Private Sub AlignToGrid(sender As Object, e As EventArgs) ' ← Snapping nur wenn aktiv If Not _SnappingEnabled OrElse Not _ShowGrid OrElse Me.DesignMode Then Return Dim ctrl As Control = CType(sender, Control) Dim x As Integer = Math.Floor(ctrl.Left / _GridSize) * _GridSize Dim y As Integer = Math.Floor(ctrl.Top / _GridSize) * _GridSize ctrl.Location = New Point(x, y) ScheduleScrollUpdate() End Sub Private Sub ScheduleScrollUpdate() If Not IsHandleCreated Then Return If Not _NeedsScrollUpdate Then _NeedsScrollUpdate = True BeginInvoke(New MethodInvoker(Sub() UpdateScrollArea() _NeedsScrollUpdate = False End Sub)) End If End Sub Protected Overrides Sub OnScroll(se As ScrollEventArgs) MyBase.OnScroll(se) ' Nach dem Scrollen vollständig neu zeichnen Invalidate() End Sub Private Sub UpdateScrollArea() Dim maxWidth As Integer = 0 Dim maxHeight As Integer = 0 For Each ctrl As Control In Me.Controls maxWidth = Math.Max(maxWidth, ctrl.Right) maxHeight = Math.Max(maxHeight, ctrl.Bottom) Next Me.AutoScrollMinSize = New Size(maxWidth, maxHeight) End Sub End Class 'Public Class ClassSnapPanel ' Inherits Panel ' Private _ShowGrid As Boolean = True ' Private _GridSize As Integer = 16 ' Public Sub New() ' Me.AutoScroll = True ' Scrollbars aktivieren ' End Sub ' Public Property GridSize As Integer ' Get ' Return _GridSize ' End Get ' Set(value As Integer) ' _GridSize = value ' Refresh() ' End Set ' End Property ' Public Property ShowGrid As Boolean ' Get ' Return _ShowGrid ' End Get ' Set(value As Boolean) ' _ShowGrid = value ' Refresh() ' End Set ' End Property ' Protected Overrides Sub OnControlAdded(e As ControlEventArgs) ' AddHandler e.Control.LocationChanged, AddressOf AlignToGrid ' AddHandler e.Control.DragDrop, AddressOf AlignToGrid ' MyBase.OnControlAdded(e) ' UpdateScrollArea() ' End Sub ' Protected Overrides Sub OnControlRemoved(e As ControlEventArgs) ' RemoveHandler e.Control.LocationChanged, AddressOf AlignToGrid ' RemoveHandler e.Control.DragDrop, AddressOf AlignToGrid ' MyBase.OnControlRemoved(e) ' UpdateScrollArea() ' End Sub ' Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs) ' If _ShowGrid Then ' ControlPaint.DrawGrid(e.Graphics, ClientRectangle, New Size(_GridSize, _GridSize), BackColor) ' End If ' MyBase.OnPaint(e) ' End Sub ' Private Sub AlignToGrid(sender As Object, e As EventArgs) ' If _ShowGrid Then ' Dim item As Control = CType(sender, Control) ' Dim x As Integer = Math.Round(item.Left / _GridSize) * _GridSize ' Dim y As Integer = Math.Round(item.Top / _GridSize) * _GridSize ' item.Location = New Point(x, y) ' UpdateScrollArea() ' End If ' End Sub ' Private Sub UpdateScrollArea() ' Dim maxWidth As Integer = 0 ' Dim maxHeight As Integer = 0 ' ' Größte X- und Y-Koordinate der enthaltenen Controls bestimmen ' For Each ctrl As Control In Controls ' Dim right As Integer = ctrl.Right ' Dim bottom As Integer = ctrl.Bottom ' If right > maxWidth Then maxWidth = right ' If bottom > maxHeight Then maxHeight = bottom ' Next ' ' Scrollbereich setzen ' Me.AutoScrollMinSize = New Size(maxWidth, maxHeight) ' End Sub 'End Class