/// <summary> /// Precalculates and caches line segments that the form can snap onto. /// </summary> private SnapGrid PrepareSizeMove(Control.ControlCollection mdiChildren) { // Ignore the possibility that the MDI client rectangle is empty. // Create a list of MDI child rectangles sorted by their z-order. (MDI child on top has index 0.) List <Rectangle> mdiChildRectangles = new List <Rectangle>(); int mdiChildCount = mdiChildren.Count; for (int mdiChildIndex = 0; mdiChildIndex < mdiChildCount; ++mdiChildIndex) { if (mdiChildren[mdiChildIndex] is Form mdiChildForm && mdiChildForm.Visible && mdiChildForm.WindowState == FormWindowState.Normal) { // Convert the bounds of this MDI child to screen coordinates. Rectangle mdiChildRectangle = mdiChildForm.Bounds; mdiChildRectangle.Offset(m_currentMdiClientScreenRectangle.Left, m_currentMdiClientScreenRectangle.Top); if (Form != mdiChildForm) { // Intersect the MDI child rectangle with the MDI client rectangle, so the form does not snap to edges outside of the visible MDI client rectangle. mdiChildRectangle = Rectangle.Intersect(mdiChildRectangle, m_currentMdiClientScreenRectangle); // Only add non-empty rectangles. if (mdiChildRectangle.Left < mdiChildRectangle.Right && mdiChildRectangle.Top < mdiChildRectangle.Bottom) { mdiChildRectangles.Add(mdiChildRectangle); } } else { // Save original rectangle, so its properties can be used to keep positions or sizes constant during sizing and/or moving. m_rectangleBeforeSizeMove = mdiChildRectangle; } } } // Calculate snappable segments and save them to arrays which can be used efficiently from within the event handlers. List <LineSegment> verticalSegments = SnapGrid.GetVerticalEdges(ref m_currentMdiClientScreenRectangle, 0); List <LineSegment> horizontalSegments = SnapGrid.GetHorizontalEdges(ref m_currentMdiClientScreenRectangle, 0); return(new SnapGrid(verticalSegments, horizontalSegments, mdiChildRectangles, InsensitiveBorderEndLength)); }
private void OwnedForm_ResizeBegin(object sender, EventArgs e) { // Precalculate size/move line segments. Form parentForm = Form.Owner; if (parentForm != null) { m_rectangleBeforeSizeMove = Form.Bounds; // Enumerate all siblings and the parent form in z-order. Form[] snapTargetForms = parentForm.OwnedForms.Union(new SingleElementEnumerable <Form>(parentForm)).ToArray(); IntPtr[] handles = snapTargetForms.Where(x => x.IsHandleCreated).Select(x => x.Handle).ToArray(); int handleCount = handles.Length; List <Form> formsInZOrder = new List <Form>(handleCount); NativeMethods.EnumWindows( new EnumThreadWindowsCallback((handle, lParam) => { int handleIndex = Array.IndexOf(handles, handle); if (handleIndex >= 0) { formsInZOrder.Add(snapTargetForms[handleIndex]); handles[handleIndex] = IntPtr.Zero; handleCount--; } return(handleCount > 0); }), IntPtr.Zero); // Now build the snap grid from all working areas edges, then the sibling rectangles. var verticalSegments = new List <LineSegment>(); var horizontalSegments = new List <LineSegment>(); foreach (Screen screen in Screen.AllScreens) { Rectangle workingArea = screen.WorkingArea; verticalSegments.AddRange(SnapGrid.GetVerticalEdges(ref workingArea, InsensitiveBorderEndLength)); horizontalSegments.AddRange(SnapGrid.GetHorizontalEdges(ref workingArea, InsensitiveBorderEndLength)); } // Add snap line segments for each sibling. List <Rectangle> siblingRectangles = new List <Rectangle>(); foreach (Form form in formsInZOrder) { if (form != Form && form.Visible && form.WindowState == FormWindowState.Normal) { Rectangle bounds = form.Bounds; // Only add non-empty rectangles. if (bounds.Left < bounds.Right && bounds.Top < bounds.Bottom) { siblingRectangles.Add(bounds); } } } m_snapGrid = new SnapGrid(verticalSegments, horizontalSegments, siblingRectangles, InsensitiveBorderEndLength); if (SnapWhileMoving) { Form.Moving += OwnedForm_Moving; } if (SnapWhileResizing) { Form.Resizing += OwnedForm_Resizing; } } }