In my program, I want the user to be able to move an MDI child window anywhere inside the MDI container but I need it to be kept completely inside the container boundary. For example, the upper left corner should never be at a location less than 0,0 when moved left or up. Currently, if I slide the child window too far left, it extends outside of the MDI container window and the MDI container shows the bottom scroll bar.

Is there a way to prevent the child window from moving outside of the boundaries of the container window? I tried adding code to the .move (see below) so that if the new location was less than 0,0 then it reset it to 0,0 but then the child window controls flicker as the window is moved beyond 0,0 and the logic moves it back to 0,0. It appears that even though the code changes the location to 0,0 and the window shows the child moved to 0,0, when the mouse moves again, the window jump back to its unmoved location.

Private Sub MyForm_Move(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Move

        If Location.X < 0 Then
            Location = New Point(0, Location.Y)
        End If
        If Location.Y < 0 Then
            Location = New Point(Location.X, 0)
        End If
    End Sub

Dani AI

Generated

is right that you must set the child form's MdiParent, but that alone does not stop the user from dragging the child so part of it sits outside the MDI client. The flicker and jump you saw come from trying to correct the position in the form's Move/LocationChanged events: those fire after Windows has already repositioned the window while the mouse is still dragging, so the OS keeps driving the drag and you get a visual jumpback.

A reliable fix is to intercept the native window messages the OS uses while dragging and clamp the child window rectangle to the MDI client before Windows repaints. Put this code in the child form class — it handles WM_MOVING (and WM_WINDOWPOSCHANGING) and keeps the child fully inside the MDI client:

Imports System.Runtime.InteropServices
Imports System.Drawing

<StructLayout(LayoutKind.Sequential)>
Private Structure RECT
    Public Left As Integer
    Public Top As Integer
    Public Right As Integer
    Public Bottom As Integer
End Structure

<StructLayout(LayoutKind.Sequential)>
Private Structure WINDOWPOS
    Public hwnd As IntPtr
    Public hwndInsertAfter As IntPtr
    Public x As Integer
    Public y As Integer
    Public cx As Integer
    Public cy As Integer
    Public flags As Integer
End Structure

Protected Overrides Sub WndProc(ByRef m As Message)
    Const WM_MOVING As Integer = &H216
    Const WM_WINDOWPOSCHANGING As Integer = &H46

    If m.Msg = WM_MOVING Then
        Dim r As RECT = CType(Marshal.PtrToStructure(m.LParam, GetType(RECT)), RECT)
        Dim clientRect As Rectangle = GetMdiClientRectInScreen()
        Dim w As Integer = r.Right - r.Left
        Dim h As Integer = r.Bottom - r.Top

        Dim minX As Integer = clientRect.Left
        Dim minY As Integer = clientRect.Top
        Dim maxX As Integer = clientRect.Right - w
        Dim maxY As Integer = clientRect.Bottom - h
        If maxX < minX Then maxX = minX
        If maxY < minY Then maxY = minY

        Dim newLeft As Integer = Math.Min(Math.Max(r.Left, minX), maxX)
        Dim newTop As Integer = Math.Min(Math.Max(r.Top, minY), maxY)

        r.Left = newLeft
        r.Top = newTop
        r.Right = newLeft + w
        r.Bottom = newTop + h

        Marshal.StructureToPtr(r, m.LParam, True)
    ElseIf m.Msg = WM_WINDOWPOSCHANGING Then
        Dim wp As WINDOWPOS = CType(Marshal.PtrToStructure(m.LParam, GetType(WINDOWPOS)), WINDOWPOS)
        Dim clientRect As Rectangle = GetMdiClientRectInScreen()
        Dim maxX As Integer = clientRect.Right - wp.cx
        Dim maxY As Integer = clientRect.Bottom - wp.cy
        If maxX < clientRect.Left Then maxX = clientRect.Left
        If maxY < clientRect.Top Then maxY = clientRect.Top

        If wp.x < clientRect.Left Then wp.x = clientRect.Left
        If wp.y < clientRect.Top Then wp.y = clientRect.Top
        If wp.x > maxX Then wp.x = maxX
        If wp.y > maxY Then wp.y = maxY

        Marshal.StructureToPtr(wp, m.LParam, True)
    End If

    MyBase.WndProc(m)
End Sub

Private Function GetMdiClientRectInScreen() As Rectangle
    If Me.MdiParent Is Nothing Then Return Screen.FromControl(Me).WorkingArea
    For Each c As Control In Me.MdiParent.Controls
        If TypeOf c Is MdiClient Then
            Dim rc As Rectangle = c.ClientRectangle
            rc.Location = c.PointToScreen(rc.Location)
            Return rc
        End If
    Next
    Return Me.MdiParent.Bounds
End Function

Notes: this clamps the child to the MDI client in screen coordinates, so no scrollbar appears and you avoid flicker. If the child is larger than the MDI client it cannot be fully contained — either prevent resizing/maximize or decide a policy (resize the child to fit or allow partial overlap). Test on multi-monitor and different DPI settings.

Recommended Answers

All 2 Replies

if you want the child form in your Mdi Parent form then try this code . it will not come out of that mdi parent form.you have to just set the Mdi parent for your child form.
let X be the Mdi Parent and Y,Z be the Chile then

''on the menu clikc of X MdiParent form i'll call y or z

Private Sub YToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SuppliersToolStripMenuItem.Click
        
        Dim y = New yform
        y.MdiParent = Me
        y.Show()
        y.BringToFront()
    End Sub

That is what I have, however, this still allows part of the child window to go beyond the side of the container. In other words, can drag the child window so the upper left corner is at location (-100, 0) and end up with only the right half of the child window showing.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.