Jak sprawić, by aplikacja Windows Form przyciągała się do krawędzi ekranu?

Ktoś tam wie, jak sprawić, by Twoja aplikacja. NET windows form była lepka / zgrzytliwa jak Winamp, aby przyciągała się do krawędzi ekranu?

Docelowym frameworkiem będzie. NET 2.0 Windows Form napisany w C#, przy użyciu VS08. Chcę dodać tę funkcjonalność do niestandardowej kontroli użytkownika, ale pomyślałem, że więcej osób skorzysta z tego, że będzie to opisane dla aplikacji i jej głównego formularza.

Dziękuję.

Author: erator, 2009-02-26

5 answers

To działało całkiem dobrze, działa na wielu monitorach, obserwuje pasek zadań:

  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;
    }
  }
 37
Author: Hans Passant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-26 18:07:33

Zaakceptowana odpowiedź przyciąga okno dopiero po zakończeniu przeciągania, podczas gdy chciałem, aby formularz stale przyciągał się do krawędzi ekranu podczas przeciągania. Oto moje rozwiązanie, luźno oparte na Paint.NET kod źródłowy :

using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Whatever
{
    /// <summary>
    /// Managed equivalent of the Win32 <code>RECT</code> structure.
    /// </summary>
    [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 + "}";
        }
    }

    /// <summary>
    /// A form that "snaps" to screen edges when moving.
    /// </summary>
    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;

        /// <summary>
        /// Flags specifying which edges to anchor the form at.
        /// </summary>
        [Flags]
        public enum SnapLocation
        {
            None = 0,
            Left = 1 << 0,
            Top = 1 << 1,
            Right = 1 << 2,
            Bottom = 1 << 3,
            All = Left | Top | Right | Bottom
        }

        /// <summary>
        /// How far from the screen edge to anchor the form.
        /// </summary>
        [Browsable(true)]
        [DefaultValue(10)]
        [Description("The distance from the screen edge to anchor the form.")]
        public virtual int AnchorDistance { get; set; } = 10;

        /// <summary>
        /// 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.
        /// </summary>
        [Browsable(true)]
        [DefaultValue(20)]
        [Description("The maximum form snapping distance.")]
        public virtual int SnapDistance { get; set; } = 20;

        /// <summary>
        /// Re-snaps the control to its current anchor points.
        /// This can be useful for re-positioning the form after
        /// the screen resolution changes.
        /// </summary>
        public void ReSnap()
        {
            SnapTo(_snapAnchor);
        }

        /// <summary>
        /// Forces the control to snap to the specified edges.
        /// </summary>
        /// <param name="anchor">The screen edges to snap to.</param>
        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<LtrbRectangle>(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);
        }
    }
}

A oto jak to wygląda:

Zrzut ekranu

 7
Author: Andrew Sun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-27 06:24:03

Wystarczy pobrać aktualną wysokość / szerokość piksela monitora, na którym się znajdujesz...

Jak określić aktywny monitor bieżącej lokalizacji kursora

... i przetworzyć zdarzenia zmiany/przeniesienia lokalizacji dla formularza. Gdy pojawi się wewnątrz, powiedzmy 25 pikseli krawędzi (lokalizacja głównego formularza.Lewa + szerokość formularza) lub wysokość (lokalizacja głównego formularza.Góra + wysokość formy), a następnie dalej i ustawić .W lewo i .Najlepszych właściwości, dzięki czemu Twoja aplikacja "dokuje" w narożniki.

Edit: Jeszcze jedna uwaga - kiedy faktycznie wykonujesz "przyciąganie", możesz również przesunąć kursor o względną odległość, aby pozostał w tym samym punkcie na pasku okna. W przeciwnym razie twoja forma może stać się gigantyczną piłką do ping-ponga między pozycją kursora a funkcją "snappy", ponieważ zdarzenia MouseMove i miejsce formy zmieniane walczą ze sobą.

 2
Author: Brandon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:12

Nie wiem, czy znalazłeś rozwiązanie, ale stworzyłem mały komponent do tego: http://www.formsnapper.net - przekracza granice procesu!

 0
Author: Daniel Mošmondor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-13 17:08:31

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
 0
Author: stax76,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-16 12:29:11