0
votes

I am working on a project which contains MDI child forms. I have make my MDI child forms stop moving when user is trying to drag them out of MDI parent borderless form's edges. But, if user insists, MDI child form flickering like crazy!!!

Note that I have already set my forms to DoubleBuffered = True and I have also add me.Refresh() and me.parentform.Refresh() at the end of event.

Any idea what else can I do?


Here is an edited example of my code...

First we have the custom title bar control and this is the needed part of it's code:

Imports System.Windows.Forms
Imports System.ComponentModel

Public Class cmosTitleBar

Region "Custom events."
    Public Event FormTitleBar_DoubleClick_Plus(sender As Object, e As EventArgs)
    Public Event FormTitleBar_MouseDown_Plus(sender As Object, e As EventArgs)
    Public Event FormTitleBar_MouseMove_Plus(sender As Object, e As EventArgs)
    Public Event FormTitleBar_MouseEnter_Plus(sender As Object, e As EventArgs)
    Public Event FormTitleBar_MouseLeave_Plus(sender As Object, e As EventArgs)
End Region

Region "Form Code."

    Dim NewPoint As New System.Drawing.Point
    Dim X, Y As Integer

Region "FormTitleBar Events."
    Private Sub FormTitleBar_DoubleClick(sender As Object, e As EventArgs) Handles FormTitleBar.DoubleClick
        RaiseEvent FormTitleBar_DoubleClick_Plus(sender, e)
        Call PreventFlickering()
    End Sub
    Private Sub FormTitleBar_MouseDown(sender As Object, e As MouseEventArgs) Handles FormTitleBar.MouseDown, FormIcon.MouseDown, MyBase.MouseDown
        If Not ParentForm.WindowState = FormWindowState.Maximized Then
            X = Control.MousePosition.X - ParentForm.Location.X
            Y = Control.MousePosition.Y - ParentForm.Location.Y
        End If
        RaiseEvent FormTitleBar_MouseDown_Plus(sender, e)
    End Sub
    Private Sub FormTitleBar_MouseMove(sender As Object, e As MouseEventArgs) Handles FormTitleBar.MouseMove, FormIcon.MouseMove, MyBase.MouseMove
        If Not ParentForm.WindowState = FormWindowState.Maximized Then
            If e.Button = Windows.Forms.MouseButtons.Left Then
                NewPoint = Control.MousePosition
                NewPoint.X -= (X)
                NewPoint.Y -= (Y)
                ParentForm.Location = NewPoint
            End If
        End If
        Call PreventChildMoveOut()
        RaiseEvent FormTitleBar_MouseMove_Plus(sender, e)
        RaiseEvent FormIcon_MouseMove_Plus(sender, e)
        Call PreventFlickering()
    End Sub
    Private Sub FormTitleBar_MouseEnter(sender As Object, e As EventArgs) Handles FormTitleBar.MouseEnter, FormIcon.MouseEnter
        If ParentForm.WindowState = FormWindowState.Normal Then
            FormTitleBar.Cursor = Cursors.NoMove2D
            FormIcon.Cursor = Cursors.NoMove2D
        Else
            FormTitleBar.Cursor = Cursors.Default
            FormIcon.Cursor = Cursors.Default
        End If
        RaiseEvent FormTitleBar_MouseEnter_Plus(sender, e)
    End Sub
    Private Sub FormTitleBar_MouseLeave(sender As Object, e As EventArgs) Handles FormTitleBar.MouseLeave
        RaiseEvent FormTitleBar_MouseLeave_Plus(sender, e)
    End Sub
End Region

End Region

Region "Custom subs."
    Private Sub PreventFlickering()
        If Me.ParentForm.IsMdiChild = True Then
            Me.ParentForm.Refresh()
            Me.ParentForm.ParentForm.Refresh()
        Else
            Me.ParentForm.Refresh()
        End If
    End Sub
    Private Sub PreventChildMoveOut()
        If ParentForm.IsMdiChild = True Then
            If ParentForm.Left < ParentForm.MdiParent.ClientRectangle.Left Then
                ParentForm.Left = ParentForm.MdiParent.ClientRectangle.Left
                If ParentForm.Top < ParentForm.MdiParent.ClientRectangle.Top Then
                    ParentForm.Top = ParentForm.MdiParent.ClientRectangle.Top
                ElseIf ParentForm.Bottom > ParentForm.MdiParent.ClientRectangle.Height - 98 Then
                    ParentForm.Top = ParentForm.MdiParent.ClientRectangle.Bottom - ParentForm.Height - 98
                End If
            ElseIf ParentForm.Right > ParentForm.MdiParent.ClientRectangle.Width Then
                ParentForm.Left = ParentForm.MdiParent.ClientRectangle.Right - ParentForm.Width
                If ParentForm.Top < ParentForm.MdiParent.ClientRectangle.Top Then
                    ParentForm.Top = ParentForm.MdiParent.ClientRectangle.Top
                ElseIf ParentForm.Bottom > ParentForm.MdiParent.ClientRectangle.Height - 98 Then
                    ParentForm.Top = ParentForm.MdiParent.ClientRectangle.Bottom - ParentForm.Height - 98
                End If
            ElseIf ParentForm.Top < ParentForm.MdiParent.ClientRectangle.Top Then
                ParentForm.Top = ParentForm.MdiParent.ClientRectangle.Top
            ElseIf ParentForm.Bottom > ParentForm.MdiParent.ClientRectangle.Height - 98 Then
                ParentForm.Top = ParentForm.MdiParent.ClientRectangle.Bottom - ParentForm.Height - 98
            End If
        End If
    End Sub
End Region

End Class

Here is the needed code of my borderless MDI parent form which contains my custom title bar control:

Public Class MainForm

Region "Form Code."
        Private Sub SettingsToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles SettingsToolStripMenuItem.Click
            SettingsForm.MdiParent = Me
            SettingsForm.Show()
        End Sub
    End Region

End Class

Into my borderless MDI child forms which also contains my custom title bar control there is no code for this action cause everything (until now) happens into custom title bar control's code.

1
MDI doesn't work right unless the border is the normal sizable border. You are fighting an uphill battle. MDI is basically an obsolete paradigm.LarsTech

1 Answers

1
votes

It is flickering because you are trying to restrict location to >= 0, and location moves to -1 then 0. Then as you try to coerce the form past your boundary, the location is really -1, 0, -1, 0, etc. You don't want to allow it to get to -1 in the first place. So instead restrict the cursor area when moving the mdi child.

To test, make a project with two forms.

  • MdiParentForm with IsMdiContainer = true
  • MdiChildForm

MdiParentForm code:

Public Class MdiParentForm

    Private child As Form

    Private Sub MdiParentForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        child = New MdiChildForm()
        child.MdiParent = Me
        child.Show()
    End Sub

End Class

MdiChildForm code:

Public Class MdiChildForm

    Private mouseIsDown As Boolean = False
    Private myParent As Form
    Private myRectangle As System.Drawing.Rectangle
    Private myCursorLocation As System.Drawing.Point
    Private myBorderWidth As Integer
    Private myTitlebarHeight As Integer

    Private Sub MdiChildForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        myParent = Me.MdiParent
    End Sub

    Private Sub MdiChildForm_MouseCaptureChanged(sender As Object, e As EventArgs) Handles Me.MouseCaptureChanged
        If mouseIsDown Then
            myRectangle = myParent.Bounds
            myCursorLocation = Me.PointToClient(Cursor.Position)
            myBorderWidth = (Me.Width - Me.ClientSize.Width) / 2
            myTitlebarHeight = Me.Height - Me.ClientSize.Height - 2 * myBorderWidth
        End If
    End Sub

    Private Sub MdiChildForm_Move(sender As Object, e As EventArgs) Handles Me.Move
        If mouseIsDown Then
            Cursor.Clip = New Rectangle(myRectangle.Left + myCursorLocation.X + myBorderWidth,
                                        myRectangle.Top + myCursorLocation.Y + myTitlebarHeight,
                                        myRectangle.Width - Me.Width - myBorderWidth,
                                        myRectangle.Height - Me.Height)
        Else
            Cursor.Clip = Nothing
        End If
    End Sub

    ' there is no event for title bar click, so use WndProc
    Protected Overrides Sub WndProc(ByRef m As Message)
        MyBase.WndProc(m)
        Select Case m.Msg
            Case &H21
                mouseIsDown = True
            Case &H22
                mouseIsDown = False
        End Select
    End Sub

End Class

Since you are using custom controls, you may need to tweak the Cursor.Clip rectangle dimensions and coordinates inside MdiChildForm_Move.