¿Cómo hacer que mi aplicación Windows Form encaje en los bordes de la pantalla?

¿Alguien por ahí sabe cómo hacer que su aplicación de Windows .net sea pegajosa / ágil como Winamp para que encaje en los bordes de la pantalla?

El marco de destino sería .NET 2.0 Windows Form escrito en C #, utilizando VS08. Estoy buscando agregar esta funcionalidad a un control de usuario personalizado, pero calculé que más personas se beneficiarían de tenerla descrita para la aplicación y su formulario principal.

Gracias.

Esto funcionó bastante bien, funciona en múltiples monitores, observa la barra de tareas:

public partial class Form1 : Form { public Form1() { InitializeComponent(); } private const int SnapDist = 100; private bool DoSnap(int pos, int edge) { int delta = pos - edge; return delta > 0 && delta < = SnapDist; } protected override void OnResizeEnd(EventArgs e) { base.OnResizeEnd(e); Screen scn = Screen.FromPoint(this.Location); if (DoSnap(this.Left, scn.WorkingArea.Left)) this.Left= scn.WorkingArea.Left; if (DoSnap(this.Top, scn.WorkingArea.Top)) this.Top = scn.WorkingArea.Top; if (DoSnap(scn.WorkingArea.Right, this.Right)) this.Left = scn.WorkingArea.Right - this.Width; if (DoSnap(scn.WorkingArea.Bottom, this.Bottom)) this.Top = scn.WorkingArea.Bottom - this.Height; } } 

La respuesta aceptada solo ajusta la ventana después de terminar el arrastre, mientras que yo quería que el formulario se ajustara continuamente a los bordes de la pantalla mientras arrastraba. Esta es mi solución, basada libremente en el código fuente de Paint.NET :

 using System; using System.ComponentModel; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; namespace Whatever { ///  /// Managed equivalent of the Win32 RECT structure. ///  [StructLayout(LayoutKind.Sequential)] public struct LtrbRectangle { public int Left; public int Top; public int Right; public int Bottom; public LtrbRectangle(int left, int top, int right, int bottom) { Left = left; Top = top; Right = right; Bottom = bottom; } public Rectangle ToRectangle() { return Rectangle.FromLTRB(Left, Top, Right, Bottom); } public static LtrbRectangle FromRectangle(Rectangle rect) { return new LtrbRectangle(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height); } public override string ToString() { return "{Left=" + Left + ",Top=" + Top + ",Right=" + Right + ",Bottom=" + Bottom + "}"; } } ///  /// A form that "snaps" to screen edges when moving. ///  public class AnchoredForm : Form { private const int WmEnterSizeMove = 0x0231; private const int WmMoving = 0x0216; private const int WmSize = 0x0005; private SnapLocation _snapAnchor; private int _dragOffsetX; private int _dragOffsetY; ///  /// Flags specifying which edges to anchor the form at. ///  [Flags] public enum SnapLocation { None = 0, Left = 1 < < 0, Top = 1 << 1, Right = 1 << 2, Bottom = 1 << 3, All = Left | Top | Right | Bottom } ///  /// How far from the screen edge to anchor the form. ///  [Browsable(true)] [DefaultValue(10)] [Description("The distance from the screen edge to anchor the form.")] public virtual int AnchorDistance { get; set; } = 10; ///  /// Gets or sets how close the form must be to the /// anchor point to snap to it. A higher value gives /// a more noticable "snap" effect. ///  [Browsable(true)] [DefaultValue(20)] [Description("The maximum form snapping distance.")] public virtual int SnapDistance { get; set; } = 20; ///  /// Re-snaps the control to its current anchor points. /// This can be useful for re-positioning the form after /// the screen resolution changes. ///  public void ReSnap() { SnapTo(_snapAnchor); } ///  /// Forces the control to snap to the specified edges. ///  /// The screen edges to snap to. public void SnapTo(SnapLocation anchor) { Screen currentScreen = Screen.FromPoint(Location); Rectangle workingArea = currentScreen.WorkingArea; if ((anchor & SnapLocation.Left) != 0) { Left = workingArea.Left + AnchorDistance; } else if ((anchor & SnapLocation.Right) != 0) { Left = workingArea.Right - AnchorDistance - Width; } if ((anchor & SnapLocation.Top) != 0) { Top = workingArea.Top + AnchorDistance; } else if ((anchor & SnapLocation.Bottom) != 0) { Top = workingArea.Bottom - AnchorDistance - Height; } _snapAnchor = anchor; } private bool InSnapRange(int a, int b) { return Math.Abs(a - b) < SnapDistance; } private SnapLocation FindSnap(ref Rectangle effectiveBounds) { Screen currentScreen = Screen.FromPoint(effectiveBounds.Location); Rectangle workingArea = currentScreen.WorkingArea; SnapLocation anchor = SnapLocation.None; if (InSnapRange(effectiveBounds.Left, workingArea.Left + AnchorDistance)) { effectiveBounds.X = workingArea.Left + AnchorDistance; anchor |= SnapLocation.Left; } else if (InSnapRange(effectiveBounds.Right, workingArea.Right - AnchorDistance)) { effectiveBounds.X = workingArea.Right - AnchorDistance - effectiveBounds.Width; anchor |= SnapLocation.Right; } if (InSnapRange(effectiveBounds.Top, workingArea.Top + AnchorDistance)) { effectiveBounds.Y = workingArea.Top + AnchorDistance; anchor |= SnapLocation.Top; } else if (InSnapRange(effectiveBounds.Bottom, workingArea.Bottom - AnchorDistance)) { effectiveBounds.Y = workingArea.Bottom - AnchorDistance - effectiveBounds.Height; anchor |= SnapLocation.Bottom; } return anchor; } protected override void WndProc(ref Message m) { switch (m.Msg) { case WmEnterSizeMove: case WmSize: // Need to handle window size changed as well when // un-maximizing the form by dragging the title bar. _dragOffsetX = Cursor.Position.X - Left; _dragOffsetY = Cursor.Position.Y - Top; break; case WmMoving: LtrbRectangle boundsLtrb = Marshal.PtrToStructure(m.LParam); Rectangle bounds = boundsLtrb.ToRectangle(); // This is where the window _would_ be located if snapping // had not occurred. This prevents the cursor from sliding // off the title bar if the snap distance is too large. Rectangle effectiveBounds = new Rectangle( Cursor.Position.X - _dragOffsetX, Cursor.Position.Y - _dragOffsetY, bounds.Width, bounds.Height); _snapAnchor = FindSnap(ref effectiveBounds); LtrbRectangle newLtrb = LtrbRectangle.FromRectangle(effectiveBounds); Marshal.StructureToPtr(newLtrb, m.LParam, false); m.Result = new IntPtr(1); break; } base.WndProc(ref m); } } } 

Y esto es lo que parece:

Captura de pantalla

Simplemente recupera la altura / ancho de píxel actual del monitor en el que estás …

Cómo determinar el monitor activo de la ubicación actual del cursor

… y procesar la ubicación cambiada / movida eventos para el formulario. Cuando te encuentres dentro, digamos 25 píxeles más o menos de un borde (la forma de tu formulario principal. Izquierda + ancho del formulario) o la altura (la forma de tu formulario principal.Top + altura del formulario), luego sigue y configura las propiedades .Left y .Top para que su aplicación “atraque” en las esquinas.

Editar: Una nota más: cuando realmente hace el “ajuste”, es posible que también desee mover la posición del cursor a la distancia relativa para que permanezca en el mismo punto en la barra de la ventana. De lo contrario, su forma puede convertirse en una pelota de ping pong gigante entre la posición del cursor y su funcionalidad “rápida”, ya que el MouseMove y la ubicación de la forma cambian los eventos que luchan entre sí.

No sé si encontraste tu solución, pero creé un pequeño componente para eso: http://www.formsnapper.net : ¡se ajusta a los límites del proceso!

https://github.com/stax76/staxrip

 Protected Overrides Sub WndProc(ByRef m As Message) Snap(m) MyBase.WndProc(m) End Sub Private IsResizing As Boolean Sub Snap(ByRef m As Message) Select Case m.Msg Case &H214 'WM_SIZING IsResizing = True Case &H232 'WM_EXITSIZEMOVE IsResizing = False Case &H46 'WM_WINDOWPOSCHANGING If Not IsResizing Then Snap(m.LParam) End Select End Sub Sub Snap(handle As IntPtr) Dim workingArea = Screen.FromControl(Me).WorkingArea Dim newPos = DirectCast(Marshal.PtrToStructure(handle, GetType(WindowPos)), WindowPos) Dim snapMargin = Control.DefaultFont.Height Dim border As Integer If OSVersion.Current >= OSVersion.Windows8 Then border = (Width - ClientSize.Width) \ 2 - 1 If newPos.Y <> 0 Then If Math.Abs(newPos.Y - workingArea.Y) < snapMargin AndAlso Top > newPos.Y Then newPos.Y = workingArea.Y ElseIf Math.Abs(newPos.Y + Height - (workingArea.Bottom + border)) < snapMargin AndAlso Top < newPos.Y Then newPos.Y = (workingArea.Bottom + border) - Height End If End If If newPos.X <> 0 Then If Math.Abs(newPos.X - (workingArea.X - border)) < snapMargin AndAlso Left > newPos.X Then newPos.X = workingArea.X - border ElseIf Math.Abs(newPos.X + Width - (workingArea.Right + border)) < snapMargin AndAlso Left < newPos.X Then newPos.X = (workingArea.Right + border) - Width End If End If Marshal.StructureToPtr(newPos, handle, True) End Sub