This would work well, I think (cellSize
is the "resolution" to which the control will "snap", assuming that each cell is square).
Prerequisites: you will need to have a PictureBox
(or some other control) that you want to move around on your Form. Put the sample code below in your form's code and attach the MouseDown
, MouseMove
and MouseUp
events of that control to these event handlers. You can attach the events using the property grid (click the events button, select the event, and use the combo box to select the corresponding event handler).
VB.NET:
Private Sub SetControlPosition(ByVal control As Control, ByVal targetPoint As Point, ByVal cellSize As Integer)
Dim roundedLocation As New Point(CInt((Math.Round(CSng(targetPoint.X) / cellSize) * cellSize)), CInt((Math.Round(CSng(targetPoint.Y) / cellSize) * cellSize)))
control.Location = roundedLocation
End Sub
If you want the control location to snap to some specific pre-defined locations, you can do like this instead (_allowedLocations
defines two allowed locations; x=50, y=50
and x=500, y=500
):
Private _allowedLocations As Point() = {New Point(50, 50), New Point(500, 500), New Point(700, 100)}
Private Sub SetControlPosition(ByVal control As Control, ByVal targetPoint As Point, ByVal cellSize As Integer)
Dim shortestDistance As Integer = Integer.MaxValue
Dim nearestLocationIndex As Integer = -1
For i As Integer = 0 To _allowedLocations.Length - 1
Dim width As Integer = targetPoint.X - _allowedLocations(i).X
Dim height As Integer = targetPoint.Y - _allowedLocations(i).Y
Dim distance As Integer = CInt(Math.Sqrt(Math.Pow(width, 2) + Math.Pow(height, 2)))
If distance < shortestDistance Then
shortestDistance = distance
nearestLocationIndex = i
End If
Next
control.Location = _allowedLocations(nearestLocationIndex)
End Sub
Example code calling the method (including moving the control with the mouse):
Private _mouseDownLocation As Point = Point.Empty
Private Sub PictureBox_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
If (e.Button And MouseButtons.Left) = System.Windows.Forms.MouseButtons.Left Then
_mouseDownLocation = e.Location
End If
End Sub
Private Sub PictureBox_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If (e.Button And MouseButtons.Left) = System.Windows.Forms.MouseButtons.Left Then
Dim target As Control = DirectCast(sender, Control)
target.Location = New Point(target.Location.X + e.Location.X - _mouseDownLocation.X, target.Location.Y + e.Location.Y - _mouseDownLocation.Y)
End If
End Sub
Private Sub PictureBox_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
If (e.Button And MouseButtons.Left) = System.Windows.Forms.MouseButtons.Left Then
Dim target As Control = DirectCast(sender, Control)
' Snap the control in place, to nearest 100x100 corner '
SetControlPosition(target, target.Location, 100)
End If
End Sub
The SetControlPosition method in C# (as an extra bonus):
private void SetControlPosition(Control control, Point targetPoint, int cellSize)
{
Point roundedLocation = new Point(
(int)(Math.Round((float)targetPoint.X / cellSize) * cellSize),
(int)(Math.Round((float)targetPoint.Y / cellSize) * cellSize)
);
control.Location = roundedLocation;
}