Search code examples
vb.netuser-controlsruntime

How to lock two forms together and moving them as a single one?


I'm creating a form at Run Time and a control is added to it. I'm choosing to locate the form2 close to form1 with New Point(Form1.Location.X + Form1.Width, Form1.Location.Y)and both form border style are set on "None", so I'm using 3 Mouse events in order to make them "draggable" (both in form1 and form2). I'm using a good code from Here

And everything works fine. So issues start when form2 is open. I created a gif Imgur gif in order to explain better . Form 1 alone id movable, form2 alone is movable. Form2 moves form1 without moving itself. The code I'm using in form1(usercontrol1) to call form2(qrcode):

    Dim qrForm = New SchermataCode()

    qrForm.ShowForm()
    Form1.TopMost = True
    qrform.dispose()

What I'm using in the control2(qrcode):

    Private Sub qrcode_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
    If e.Button = MouseButtons.Left Then
        startPosition = e.Location
    End If
End Sub
Private Sub qrcode_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
    If e.Button = MouseButtons.Left Then
        Form1.Location = New Point(
            Form1.Left + (e.X - startPosition.X),
            Form1.Top + (e.Y - startPosition.Y))
    End If
End Sub
Private Sub PictureBox10_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox10.MouseMove
    If e.Button = MouseButtons.Left Then
        Form1.Location = New Point(
            Form1.Left + (e.X - startPosition.X),
            Form1.Top + (e.Y - startPosition.Y))
    End If
End Sub

Private Sub PictureBox10_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox10.MouseDown
    If e.Button = MouseButtons.Left Then
        startPosition = e.Location
    End If
End Sub

This is how I'm generating a new form and adding control2 (qrcode)

    Option Strict On

Public Class SchermataCode
    Implements IDisposable

    Private qrForm As Form = Nothing
    Private qr As qrcode = Nothing
    Private startPosition As Point = Point.Empty
    ' Dim qrcode As New qrcode
    Public Sub New()
        qrForm = New Form() With {
            .FormBorderStyle = FormBorderStyle.None,
            .StartPosition = FormStartPosition.Manual,
            .Location = New Point(Form1.Location.X + Form1.Width, Form1.Location.Y),
            .AutoScaleMode = AutoScaleMode.None,
            .Icon = DirectCast(My.Resources.ResourceManager.GetObject("_" & My.Settings.icona), Icon),
            .Dock = DockStyle.Fill,
            .TopMost = True
        }

        qr = New qrcode()
        AddHandler qr.MouseDown, AddressOf qrCode_MouseDown
        AddHandler qr.MouseMove, AddressOf qrCode_MouseMove
        AddHandler qr.DoubleClick, AddressOf qrCode_OnDoubleClick
        qrForm.Controls.Add(qr)
    End Sub

    Public Function ShowForm() As Image
        qrForm.ClientSize = qr.Size
        qrForm.Showdialog
        Form1.TopMost = True
    End Function


    Private Sub qrCode_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
        If e.Button = MouseButtons.Left Then
            startPosition = e.Location
        End If
    End Sub

    Private Sub qrCode_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
        If e.Button = MouseButtons.Left Then
            qrForm.Location = New Point(
                qrForm.Left + (e.X - startPosition.X),
                qrForm.Top + (e.Y - startPosition.Y))
        End If
    End Sub

    Private Sub qrCode_OnDoubleClick(ByVal sender As Object, ByVal e As EventArgs)
        qrForm.Close()
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    Protected Overridable Sub Dispose(disposing As Boolean)
        If disposing Then
            If qrForm IsNot Nothing Then
                RemoveHandler qr.DoubleClick, AddressOf qrCode_OnDoubleClick
                RemoveHandler qr.MouseDown, AddressOf qrCode_MouseDown
                RemoveHandler qr.MouseMove, AddressOf qrCode_MouseMove
            End If
            qr?.Dispose()
            qrForm?.Dispose()
        End If
    End Sub
End Class

Anyone has any idea? I'm looking to open form2 close to form1, drag both together and If form2 is Double clicked then close it and leave just form1 open. Form1 doesn't drag form2 when together.

Thanks


Solution

  • For anyone reading this question/answer, a lot was done via CHAT, and this was not the final solution.

    So my question is: I can't declare again "Dim qrForm = New SchermataCode()" in form1(usercontrol)Mouse_move as I'm already calling it In a button , so how can I make it public ? I tried to insert that under Public Class UserControl1 but it goes on StackOverflow.. Thanks

    This is a design issue involving Scope.

    Move the declaration of "qrForm" to UserControl level, so it is not in the Button handler:

    ' ... code in UserControl (that is housed by the Main Form) ...
    
    Private qrForm As SchermataCode
    
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If IsNothing(qrForm) Then
            qrForm = New SchermataCode()
        End If
        qrForm.ShowForm()
        Form1.TopMost = True
    End Sub
    

    Not that I'm checking to see if "qrForm" is nothing (null) or if it has been disposed (closed) before creating it.

    In your handlers where you you want to move that secondary form, you'd do something similar before attempting to use it:

    ' ... code in UserControl (that is housed by the Main Form) ...
    
    ' The Foo() below could be any handler (like a MouseMove)
    Private Sub Foo() 
        If (Not IsNothing(qrForm)) AndAlso (Not qrForm.IsDisposed) Then
    
            ' ... do something with "qrForm" in here (like move it) ...
    
        End If
    End Sub
    

    ----- After watching the GIF posted at the bottom of the comments -----

    Good grief...I see what is happening now. Your variable names leave much to be desired. In UserControl1, you have a variable called qrForm of type SchermataCode. Then, inside class SchermataCode, you have ANOTHER variable called qrForm which is the actual form that you want to manipulate! We are SO CLOSE!

    First, in class SchermataCode, change the declaration of qrForm from Private to Public:

    Public Class SchermataCode
        Implements IDisposable
    
        Public qrForm As Form = Nothing
    
        ' ... the rest of the existing code ...
    
    End Class
    

    Now, over in UserControl1, we want to access that "inner" qrForm above. This will look weird because you named the variables the same:

    ' ... inside the PictureBox5_MouseMove() method of UserControl1 ...
    
    If Not IsNothing(qrForm) Then   
       ' Let's make a variable that points directly to the secondary Form:
        Dim frm As Form = qrForm.qrForm ' <--- use better names next time!  =)
    
        ' Now let's move it:
        frm.Location = New Point(
            frm.Left + (e.X - startPosition.X),
            frm.Top + (e.Y - startPosition.Y))
    End If
    

    Hope that solves the issue now.