那里的任何人都知道如何使你的.net窗口形成应用程序像Winamp一样粘性/敏捷,所以它会捕捉到屏幕的边缘?
目标框架是使用VS08用C#编写的.NET 2.0 Windows Form.我希望将此功能添加到自定义用户控件,但我想更多的人将从为应用程序及其主要表单描述它将受益.
谢谢.
这工作得很好,适用于多个监视器,观察任务栏:
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; } }
接受的答案仅在完成拖动后捕捉窗口,而我希望表单在拖动时连续捕捉到屏幕边缘.这是我的解决方案,松散地基于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 [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 + "}"; } } ///RECT
structure. ////// 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); } } }
这是它的样子: