Share via


I can't get me.close() to work in Visual Basic 2013

Question

Monday, November 27, 2017 4:42 PM

I am building a project using Visual Basic in Visual Studio 2013 and I can’t get me.close to work for me.  I have two forms, a main form and a second form.  I launch my second form from my main form.  In the second form I have placed a me.close in several routines as a way to error out of the second form and get back to the main form.   None of these me.close statements work, the program just keeps chugging along.  I also placed a me.close in a routine that handles the "DONE" button in the second form (this is the only me.close that works).   What am I doing wrong?  Why doesn’t me.close work (except for the instance of the DONE button).

Can anyone help me understand what is going on?

All replies (31)

Wednesday, November 29, 2017 6:28 PM ✅Answered

Think that through and see if you can apply some of it to your own?

"A problem well stated is a problem half solved.” - Charles F. Kettering

Frank.  Thanks very much for your help and the time you spent building this simplified version of a dual form project.  It helped me immensely.   I built this, tested it and then made a few modifications to the code to help me understand how the Me.Close() method  actually works (since I can’t find anything explicitly written to explain the behavior) and its impact on Form2. 

Here is the modified code and forms.  I added a button in Form1 to simulate passing bad data to Form2 and I added a button in button in Form2 to simulate generating an error in Form2.  To follow what was going on in the project I used various messages  to indicate the path through the code and I also used break points and the “Step Into” debug feature of Visual Studio. The code segments that I added to what you sent me are labeled with “I added this TJB“  In this way I could restructure the code by commenting out and/or uncommenting various code segments and quickly rerunning it to observe the results.

Form1 Code:

Public Class Form1

    Public Shared ErrorFlg As Boolean = False

    Private Sub btnSelectTheColor_Click(sender As Object, e As EventArgs) Handles btnSelectTheColor.Click
        Dim colors() As Color = _
     {Color.Red, Color.Green, Color.Blue}
        ErrorFlg = False  'I added this TJB
        Me.Hide() 'I added this TJB
        Using f2 As New Form2(colors)
            f2.ShowDialog()
            If Not f2.UserCancel Then
                If f2.UserSelection IsNot Nothing Then
                    MessageBox.Show("The user selected the color " & _
                                    f2.UserSelection.ToString)
                End If
            End If
        End Using
        Me.Show() 'I added this TJB
    End Sub

    Private Sub btnCheckForError_Click(sender As Object, e As EventArgs) Handles btnCheckForError.Click 'I added this Sub TJB
        Dim colors() As Color = _
{Color.Red, Color.Green, Color.Blue}
        ErrorFlg = True
        Me.Hide()
        Using f2 As New Form2(colors)
            f2.ShowDialog()
            If Not f2.UserCancel Then
                If f2.UserSelection IsNot Nothing Then
                    MessageBox.Show("The user selected the color " & _
                                    f2.UserSelection.ToString)
                End If
            End If
        End Using
        Me.Show()
        ErrorFlg = False
    End Sub

    Private Sub btnEXIT_Click(sender As Object, e As EventArgs) Handles btnEXIT.Click 'I added this TJB
        End
    End Sub


End Class

Form 2 Code:

Public Class Form2

    Private _colorChoices As IEnumerable(Of Color)
    Private _userCancel As Boolean = True
    Private _userSelection As Nullable(Of Color)
    Dim YouGotAnError As Boolean = False




    Public Sub New(ByVal colors As IEnumerable(Of Color))
        InitializeComponent()


        If colors Is Nothing OrElse colors.Count <> 3 Then
            Me.Close()
        Else
            _colorChoices = colors
        End If

    End Sub

    Private Sub _
        Form2_Load(sender As System.Object, _
                   e As System.EventArgs) _
                   Handles MyBase.Load

        With Me
            .AcceptButton = btn_OK
            .CancelButton = btn_Cancel
        End With

        btnRed.Text = _colorChoices(0).ToString
        btnGreen.Text = _colorChoices(1).ToString
        btnBlue.Text = _colorChoices(2).ToString

        'Go check to see if I have an error - I added this TJB
        CheckForPassingAnError()
        MsgBox("You checked for an error by calling CheckForPassingAnError() in the Form2_Load Sub")
        If YouGotAnError = True Then

            'Me.Close()
            'MsgBox("This is after the Me.Close in the Form2_Load Sub")
        End If
        MsgBox("This is just before the End Sub in the Form2_Load Sub")

    End Sub

    Private Sub _
        Form2_Shown(sender As Object, _
                    e As System.EventArgs) _
                    Handles Me.Shown

        btnRed.Checked = False
        btnGreen.Checked = False
        btnBlue.Checked = False

        btn_OK.Enabled = False

    End Sub

    Private Sub _
        CheckedChanged(sender As Object, _
                       e As System.EventArgs) Handles _
                       btnRed.CheckedChanged, _
                       btnGreen.CheckedChanged, _
                       btnBlue.CheckedChanged

        If btnRed.Checked Then
            _userSelection = _colorChoices(0)

        ElseIf btnGreen.Checked Then
            _userSelection = _colorChoices(1)

        ElseIf btnBlue.Checked Then
            _userSelection = _colorChoices(2)
        End If

        btn_OK.Enabled = True

    End Sub

    Private Sub _
        btn_OK_Click(sender As System.Object, _
                     e As System.EventArgs) _
                     Handles btn_OK.Click

        If _userSelection.HasValue Then
            _userCancel = False
            Me.Close()
        End If

    End Sub

    Private Sub _
        btn_Cancel_Click(sender As System.Object, _
                         e As System.EventArgs) _
                         Handles btn_Cancel.Click

        Me.Close()

    End Sub

    Public ReadOnly Property UserCancel As Boolean
        Get
            Return _userCancel
        End Get
    End Property

    Public ReadOnly Property UserSelection As Nullable(Of Color)
        Get
            Return _userSelection
        End Get
    End Property

    Private Sub btnError_CheckedChanged(sender As Object, e As EventArgs) Handles btnError.CheckedChanged 'I added this TJB
        MsgBox("You know this is not a valid selection")
        Me.Close()
        'Me.Refresh()
        MsgBox("This is after the Me.Close() in the Other - An Error button handler")
    End Sub

    Private Sub CheckForPassingAnError()  'I added this TJB
        If Form1.ErrorFlg = True Then

            MsgBox("You have an error.  Correct this")
            YouGotAnError = True
            'MsgBox("This is before the Me.Close to test the Exit.Sub statement")

            Me.Close()
            MsgBox("This is after the Me.Close in the CheckForPassingAnError Sub")

            Exit Sub
            MsgBox("This is after the Me.Close and Exit Sub in the CheckForPassingAnError Sub")

        End If
    End Sub


End Class

What I found is that the Me.Close() statement does not immediately force a close of the form and therefore cannot be used to close the form in the middle of a subroutine.

The best way I can explain this is to think of my project as two parts.  These parts are the “Form” presentation view and the “Project Code”.  The Project Code is what I wrote to perform the functions I need.  That code is executed when I press a button on the Form.  After the Project Code is executed the project goes back to an idle state passing control back to the Form waiting for me to again press a button. 

The Form is what I see on the screen.  The Form sits idle monitoring the buttons for presses and when it detects those presses it transfers control to my Project Code to execute the code that I have written and when my Project Code has finished executing, control is transferred back to the Form.

In this way I can think of the Me.Close() method as simply setting a flag that the Form monitors and acts on when control is passed to it.

The issue I had was an incomplete understanding of how the Me.Close() actually works.  So with that in mind I need to go back to my original project and refactor some of the routines.

I also hope this helps anyone else that is scratching their head about the Me.Close() behavior.


Monday, November 27, 2017 4:46 PM

Hi

Saying 'a way to error out of the form' doesn't sound quite like a good idea to me.

Put a break point at each of the Me.Close statements and see if they are actually being reached.

Regards Les, Livingston, Scotland


Monday, November 27, 2017 5:11 PM

In windows forms, means Me.Close that the class object closes and gives control back to the class object that did call it. 

As you know that the application framework contains a startup module which does

1.Run the main Form and gives the control to it
2.Exit application. 

Then it should be easy to understand what you would do. 

Be aware that exit the application from the application framework is the only right way to do.  

Success
Cor


Monday, November 27, 2017 5:15 PM

I am building a project using Visual Basic in Visual Studio 2013 and I can’t get me.close to work for me.  I have two forms, a main form and a second form.  I launch my second form from my main form.  In the second form I have placed a me.close in several routines as a way to error out of the second form and get back to the main form.   None of these me.close statements work, the program just keeps chugging along.  I also placed a me.close in a routine that handles the "DONE" button in the second form (this is the only me.close that works).   What am I doing wrong?  Why doesn’t me.close work (except for the instance of the DONE button).

Can anyone help me understand what is going on?

Are you showing the other form modally or modelessly?

Can you show some of the relevant code?

"A problem well stated is a problem half solved.” - Charles F. Kettering


Monday, November 27, 2017 5:17 PM

Yes I did that and I have followed through the code step by step once it hits the breack by using the "step into" in the debug mode.  I also placed msgbox statements in the code to signify when I reach certain points to test where it is going in the code.  I also tried putting a btnDone.PerformClick() in place of the me.close thinking it would go to the btnDone handler and then close but that does not work either (yes it gets to the btnDone handler but it does not close).  The only time it closes is when I click the DONE button.


Monday, November 27, 2017 5:27 PM

Hi

So, you still want to keep the code you have secret! You are asking us to guess.

Regards Les, Livingston, Scotland


Monday, November 27, 2017 5:50 PM

I am building a project using Visual Basic in Visual Studio 2013 and I can’t get me.close to work for me.  I have two forms, a main form and a second form.  I launch my second form from my main form.  In the second form I have placed a me.close in several routines as a way to error out of the second form and get back to the main form.   None of these me.close statements work, the program just keeps chugging along.  I also placed a me.close in a routine that handles the "DONE" button in the second form (this is the only me.close that works).   What am I doing wrong?  Why doesn’t me.close work (except for the instance of the DONE button).

Can anyone help me understand what is going on?

Are you showing the other form modally or modelessly?

Can you show some of the relevant code?

"A problem well stated is a problem half solved.” - Charles F. Kettering

Hi Charles.  It shows the second form as a modal dialog box.  I'm not sure what the difference is.


Monday, November 27, 2017 5:54 PM

Hi Charles.  It shows the second form as a modal dialog box.  I'm not sure what the difference is.

I'm Frank. ;-)

*****

That's good then.

What you'll want to do is to create a NEW instance of that second form and pass in anything that it needs through the constructor and pass out anything that the calling form needs back.

Normally I'll set a class-scoped boolean named "_userCancel" that I default to true. It's only false in the handler for the "OK" button and the code controls whether or not that button is enabled.

I don't know if this helps or not but if you want to explain what your program does then maybe a bit of refactoring might be in order here?

"A problem well stated is a problem half solved.” - Charles F. Kettering


Monday, November 27, 2017 6:15 PM

Hi

So, you still want to keep the code you have secret! You are asking us to guess.

Regards Les, Livingston, Scotland

Hi Les

So here is some of the relevant code segments:

This first segment  is the call to the second form (called ImgPreviewForm) from the main form (called MainFDForm).  This calls the public Class coverView (in the second form).  When I click the DONE button in the second form it closes the second form and returns to the main form and I get the message “returned from preview”

    Private Sub BtnReviewCovers_Click(sender As Object, e As EventArgs) Handles btnReviewCovers.Click
        'TODO: Done 078: Fix an unhandled exception error if there is no Path Specified in hilevelfolder txtbxFolderPath.  Coded in 1.5.2.1g
        'TODO: 093: Fix this so that if it points to a folder that does not exist it will flag the error In v1.5.3.0a it is an unhandled exception error
        'TODO: 097: Add a From To check to set bounds for displaying Images
        If txtbxFolderPath.Text <> "" Then
            Dim viewCovers As New coverView()
            viewCovers.HiLvlImgFldr = txtbxFolderPath.Text 'Sets the HiLvlImgFldr variable in the viewCovers Class
            viewCovers.DupsReviewFlg = DupliFoldersFlg
            viewCovers.HiLvlImgFldrRcv = txtbxDestFldr.Text 'Sets the folder for where the duplicates are located TD070
            Me.Hide()
            viewCovers.ShowDialog()

            MsgBox("returned from preview") 'Part of debugging TD109

            Me.Show()

        Else
            MsgBox("You need to provide a path for the images")
        End If
    End Sub

This code segment is from the second form  and is an example of using me.close that does not work.  I have used the debug on this code segment and found that it ignores the me.close and just keeps chugging through the code.  I do get the "Closed the form with tststring 1 = ”  message but it does not close and keeps right on through the code.

    Private Sub LoadImgsInfoToArrays(ByVal fldrPntr)
        Dim i As Integer
        tooManyImgsFlg = False
        i = 0
        While i <= imgNamesCnt(fldrPntr) 'Clear The Image arrays first
            imgNames(fldrPntr, i) = Nothing
            imgStatsArray(fldrPntr, i, 0) = 0
            imgStatsArray(fldrPntr, i, 1) = 0
            imgStatsArray(fldrPntr, i, 2) = 0
            i += 1
        End While
        foundImgCount = 0
        For Each foundImg As String In My.Computer.FileSystem.GetFiles(imgFldrs(fldrPntr, 0))
            Dim foundImgStats As New System.IO.FileInfo(foundImg)
            If XPRN_File_Discovery.XPRNFilDis.extensionsImages.Contains(foundImgStats.Extension.ToLower) Then
                imgNames(fldrPntr, foundImgCount) = foundImgStats.Name
                foundImgCount += 1
                If foundImgCount > 1000 Then
                    tooManyImgsFlg = True
                    tooLargeSetFldrName = imgFldrs(fldrPntr, 0)
                End If
            End If
        Next
        imgDispPnt(fldrPntr) = 1
        imgNamesCnt(fldrPntr) = foundImgCount
        If foundImgCount = 0 Then 'You have no Images in this folder.  Error out and quit
            'TODO:  109: Need to debug the system error that occurs when I get this "no images in "  message 

            tstString1 = imgFldrs(fldrPntr, 0)  'for TD109 Debug

            MsgBox("There are no images in " & imgFldrs(fldrPntr, 0) & " to set up for image previews.  Please correct this and try again", MsgBoxStyle.Critical)

            'btnDone.PerformClick() 'test for TD109 see if it closes by going to DONE

            Me.Close()

            MsgBox("Closed the form with tststring 1 = " & tstString1) 'debug for TD109 

        End If
    End Sub

I also have several other places where I try to use Me.Close they don't work either.

This code segment is from the second form and is the DONE button handler (that works when I click the DONE button the second form)  That is it closes the second form and returns me to the first form:

    Private Sub BtnDone_Click(sender As Object, e As EventArgs) Handles btnDone.Click 'Close out all the Images before exiting
        Grp0PictBxImgDispose()
        Grp1PictBxImgDispose()
        Me.Close()
    End Sub

Still scratching my head over this me.close conundrum.  Any suggestions?


Monday, November 27, 2017 6:23 PM

Hi

Try changing the

viewCovers.ShowDialog()

to

viewCovers.Show()

and see if the .Close lines work then.

Regards Les, Livingston, Scotland


Monday, November 27, 2017 6:57 PM

Sorry Les that did not work. It now hides the first form, opens the second form performs some of the functions and right away it goes back to the first form and redisplays the first form without hitting any of the me.close statements (I put a break point at every me.close statement).  I am now left with two forms open (displayed) where I only wanted one or the other.


Monday, November 27, 2017 6:58 PM

Sorry Les that did not work. It now hides the first form, opens the second form performs some of the functions and right away is goes back to the first form and redisplays the first form without hitting any of the me.close statements (I put a break point at every me.close statement).  I am now left with two forms open (displayed) where I only wanted one or the other.

Now you know the difference between modal and modeless. ;-)

"A problem well stated is a problem half solved.” - Charles F. Kettering


Monday, November 27, 2017 7:08 PM

You obviously did not read what I wrote. 

If you click on the second form as done then it returns control to the first form. 

That is 100% correct as it should be. 

Set before that close the dialogresult of that dialogform to dialogresult.cancel

Me.DialogResult = DialogResult.Cancel

and use this code on your mainform.

        If txtbxFolderPath.Text = "" Then
            MsgBox("You need to provide a path for the images")
            Return
        End If
        Me.Hide()
        Using viewCovers As New coverView()
            viewCovers.HiLvlImgFldr = txtbxFolderPath.Text 'Sets the HiLvlImgFldr variable in the viewCovers Class
            viewCovers.DupsReviewFlg = DupliFoldersFlg
            viewCovers.HiLvlImgFldrRcv = txtbxDestFldr.Text 'Sets the folder for where the duplicates are located TD070

            If viewCovers.ShowDialog <> dialogresult.Cancel Then
                Me.Close()
            End If
        End Using

Success
Cor


Monday, November 27, 2017 7:16 PM

Show some details about viewCovers.ShowDialog() and about the calling of LoadImgsInfoToArrays. Maybe there are several unneeded instances of ImgPreviewForm.


Monday, November 27, 2017 7:18 PM

TJB - here is an example that might help.  The main form (Form1) has two buttons, and the other form (Form2) has one button.

Form2 code

Public Class Form2
    Public Sub New(CloseType As DialogResult)
        InitializeComponent()
        Me._close = CloseType
    End Sub

    Public _close As DialogResult

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Me.Close()
    End Sub

    Private Sub Form2_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
        Me.DialogResult = _close
    End Sub
End Class

Form1 code

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ' ShowDialog version
        Static f2 As Form2
        f2 = New Form2(Windows.Forms.DialogResult.OK)
        Dim dr As DialogResult = f2.ShowDialog()
        Debug.Write(f2.IsDisposed)
        Debug.WriteLine(dr)
        f2.Dispose()
        dr = Nothing
    End Sub

    Private f2Task As Task
    Private Async Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        ' Show version
        If f2Task IsNot Nothing Then Exit Sub
        f2Task = F2Show()
        Await f2Task
        ' Stop
        f2Task.Dispose()
        f2Task = Nothing
    End Sub

    Private Async Function F2Show() As Task
        Dim f2 As Form2
        Dim t As Task = Task.Run(Sub()
                                     f2 = New Form2(Windows.Forms.DialogResult.OK)
                                     Me.Invoke(Sub()
                                                   f2.Show()
                                               End Sub)
                                     While f2._close <> f2.DialogResult
                                         Threading.Thread.Sleep(100)
                                     End While
                                 End Sub)
        Await t
        ' Stop
    End Function
End Class

Give it a try and see if it helps. Both button 1 and two do the same thing, show one instance of the form.

"Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it" - MSDN User JohnWein

Multics - An OS ahead of its time.Serial Port Info


Monday, November 27, 2017 7:18 PM

Show some details about viewCovers.ShowDialog() and about the calling of LoadImgsInfoToArrays. Maybe there are several instances of ImgPreviewForm.

Why about that the OP wrote all there is in my perception. The problem is obvious. It will never close only because of a close in a child form it returns control to the higher class. 

Success
Cor


Monday, November 27, 2017 7:21 PM

This seems very strange.

Try this in a new project to rule out stuff interfering with this small demo. Project should have two forms, Form1 and Form2.

Form1 has a single button with the following code

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim f As New Form2
        Try
            Hide()
            f.ShowDialog()
        Finally
            Show()
            f.Dispose()
        End Try
    End Sub
End Class

Form 2 has two buttons, first button in the property window set DialogResult to Ok, in the second button Close.

Both button1 and button2 will close the child form and display the caller (form1)

If you do this in your project (following the pattern above) and still have issues there is something we have not seen causing the issue.

Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
VB Forums - moderator


Monday, November 27, 2017 7:33 PM

Hi Charles.  It shows the second form as a modal dialog box.  I'm not sure what the difference is.

I'm Frank. ;-)

*****

That's good then.

What you'll want to do is to create a NEW instance of that second form and pass in anything that it needs through the constructor and pass out anything that the calling form needs back.

Normally I'll set a class-scoped boolean named "_userCancel" that I default to true. It's only false in the handler for the "OK" button and the code controls whether or not that button is enabled.

I don't know if this helps or not but if you want to explain what your program does then maybe a bit of refactoring might be in order here?

"A problem well stated is a problem half solved.” - Charles F. Kettering

Sorry about that Frank.

I have placed a couple of code segments in this thread to show what I am trying to do.  In my project I am working with Images and Image folders.  Right now I have two forms. I only want to display and work on one form at a time.  The first form allows me to specify where the image folders are on my disk, web, etc. and allows me to extract images from rar files, modify (rescale) images and/or modify some of the image meta data.  With my project I managed to launch a second form that I use to display thumbnails of images allowing me to scroll through images, rename images or delete images and/or folders.  I launch this second form when I want to preview images from folders or when I encounter duplicate images or duplicate folders allowing me to delete images or folders.

There are instances in the second form when I want to stop any further processing in the second form and immediately exit back to the first form. These are instances where I:

  • Found no images to display in the folders (or the rar files) (this is an error condition)
  • Completed the disposition of duplicates (this is not an error just the end of the disposition process).

There are a few other instances and/or error conditions.  But the key here is that the only way to get back to the first form is by clicking on the second form’s DONE button (ie: the me.close does not work unless it is executed from the btnDone handler).

I am up for refactoring code if I could understand how to get back to the first form immediately from the code not from a button click.


Monday, November 27, 2017 7:40 PM

Hi Charles.  It shows the second form as a modal dialog box.  I'm not sure what the

Sorry about that Frank.

I have placed a couple of code segments in this thread to show what I am trying to do.  In my project I am working with Images and Image folders.  Right now I have two forms. I only want to display and work on one form at a time.  The first form allows me to specify where the image folders are on my disk, web, etc. and allows me to extract images from rar files, modify (rescale) images and/or modify some of the image meta data.  With my project I managed to launch a second form that I use to display thumbnails of images allowing me to scroll through images, rename images or delete images and/or folders.  I launch this second form when I want to preview images from folders or when I encounter duplicate images or duplicate folders allowing me to delete images or folders.

There are instances in the second form when I want to stop any further processing in the second form and immediately exit back to the first form. These are instances where I:

  • Found no images to display in the folders (or the rar files) (this is an error condition)
  • Completed the disposition of duplicates (this is not an error just the end of the disposition process).

There are a few other instances and/or error conditions.  But the key here is that the only way to get back to the first form is by clicking on the second form’s DONE button (ie: the me.close does not work unless it is executed from the btnDone handler).

I am up for refactoring code if I could understand how to get back to the first form immediately from the code not from a button click.

That definitely sounds like you want to use a modal form them, not a modelss.

Like I said earlier, I'd strongly suggest that you create a NEW instance of that other form; instead of .ShowDialog, you'll do something like this (in the calling form):

Using f2 As New Form2()
    f2.ShowDialog
End Using

That's a shortcut that will close/dispose things when the "End Using" exits. You can pass things in (and it sounds like you will need to) and pass things out (which you probably want to do).

There are a lot of replies here and I'm sure that it'll all get confusing after a while, but once you want to let's re-work that second form, then let me know and I'll help you with that (if you want).

If you'd like for me to show you what I mean about a constructor, passing things in, and passing things out, we can start there -- just let me know.

"A problem well stated is a problem half solved.” - Charles F. Kettering


Monday, November 27, 2017 7:41 PM

You obviously did not read what I wrote. 

If you click on the second form as done then it returns control to the first form. 

That is 100% correct as it should be. 

Set before that close the dialogresult of that dialogform to dialogresult.cancel

Me.DialogResult = DialogResult.Cancel

and use this code on your mainform.

        If txtbxFolderPath.Text = "" Then
            MsgBox("You need to provide a path for the images")
            Return
        End If
        Me.Hide()
        Using viewCovers As New coverView()
            viewCovers.HiLvlImgFldr = txtbxFolderPath.Text 'Sets the HiLvlImgFldr variable in the viewCovers Class
            viewCovers.DupsReviewFlg = DupliFoldersFlg
            viewCovers.HiLvlImgFldrRcv = txtbxDestFldr.Text 'Sets the folder for where the duplicates are located TD070

            If viewCovers.ShowDialog <> dialogresult.Cancel Then
                Me.Close()
            End If
        End Using

Success
Cor

Hi Cor.  I read what you wrote but I did not understand it and after this I still don't.


Monday, November 27, 2017 8:07 PM

Frank,  that would be great, I would welcome your help.  I don’t think I have a problem passing things in and out as currently I am using public shared variables or I use Statements like:

            viewCovers.HiLvlImgFldr = txtbxFolderPath.Text 'Sets the HiLvlImgFldr variable in the viewCovers Class
            viewCovers.DupsReviewFlg = DupliFoldersFlg
            viewCovers.HiLvlImgFldrRcv = txtbxDestFldr.Text 'Sets the folder for where the duplicates are located TD070

to set variables in the second form. 

I know I could pass those through in the viewCovers.ShowDialog() statement as byval but that does not seem to be the issue (since all the variables are set correctly when I get to the second Form).  I am just stumped as to how to get the second form code to stop executing, close the second form and return to the first when I use “me.close” in the code (other than when I press the DONE button).


Monday, November 27, 2017 8:10 PM

Frank,  that would be great, I would welcome your help.  I don’t think I have a problem passing things in and out as currently I am using public shared variables or I use Statements like:

            viewCovers.HiLvlImgFldr = txtbxFolderPath.Text 'Sets the HiLvlImgFldr variable in the viewCovers Class
            viewCovers.DupsReviewFlg = DupliFoldersFlg
            viewCovers.HiLvlImgFldrRcv = txtbxDestFldr.Text 'Sets the folder for where the duplicates are located TD070

to set variables in the second form. 

I know I could pass those through in the viewCovers.ShowDialog() statement as byval but that does not seem to be the issue (since all the variables are set correctly when I get to the second Form).  I am just stumped as to how to get the second form code to stop executing, close the second form and return to the first when I use “me.close” in the code (other than when I press the DONE button).

Give me a little while and I'll put together an example that has nothing to do with what you're doing other than I'll use a second form.

Doing it like that, you won't get confused about your actual application and can instead just focus on this little one.

I think that once you "get it" with the little one, you'll start to see what's going on in your larger one.

"A problem well stated is a problem half solved.” - Charles F. Kettering


Monday, November 27, 2017 8:23 PM

Frank,  that would be great, I would welcome your help.  I don’t think I have a problem passing things in and out as currently I am using public shared variables or I use Statements like:

            viewCovers.HiLvlImgFldr = txtbxFolderPath.Text 'Sets the HiLvlImgFldr variable in the viewCovers Class
            viewCovers.DupsReviewFlg = DupliFoldersFlg
            viewCovers.HiLvlImgFldrRcv = txtbxDestFldr.Text 'Sets the folder for where the duplicates are located TD070

to set variables in the second form. 

I know I could pass those through in the viewCovers.ShowDialog() statement as byval but that does not seem to be the issue (since all the variables are set correctly when I get to the second Form).  I am just stumped as to how to get the second form code to stop executing, close the second form and return to the first when I use “me.close” in the code (other than when I press the DONE button).

Give me a little while and I'll put together an example that has nothing to do with what you're doing other than I'll use a second form.

Doing it like that, you won't get confused about your actual application and can instead just focus on this little one.

I think that once you "get it" with the little one, you'll start to see what's going on in your larger one.

"A problem well stated is a problem half solved.” - Charles F. Kettering

Frank, that would help immensely.  Thank You 


Monday, November 27, 2017 8:34 PM

Hi Cor.  I read what you wrote but I did not understand it and after this I still don't.

This is the rference:
"Unlike non-modal forms, the Close method is not called by the .NET Framework when the user clicks the close form button of a dialog box or sets the value of the DialogResult property."
https://msdn.microsoft.com/en-us/library/c7ykbedk%28v=vs.110%29.aspx

So the problem is not that the form is failing to close, it is failing to hide.  You need to look for something in the form that prevents it from hiding.  Or, dispose of the form after control returns to the calling form.


Monday, November 27, 2017 8:39 PM

Frank,  that would be great, I would welcome your help. 

Ok,

This is what I have, nonsensical though it is. I've got a main form (Form1.vb) and with the click of a button I'm going to pass in three colors which are defined in a collection. My auxiliary form (Form2.vb) will take these three colors and populate the text of three RadioButtons. The second form also has an "OK" button and a "Cancel" button:

The thing to keep up with here is that Form2 is shown modally; Form1's code won't resume until after Form2 has been dismissed so here's the code for Form1:

Public Class Form1
    Private Sub _
        Form1_Load(sender As System.Object, _
                   e As System.EventArgs) _
                   Handles MyBase.Load

        ' Initialization here if applicable...

    End Sub



    Private Sub _
        btn_SelectColor_Click(sender As System.Object, _
                              e As System.EventArgs) _
                              Handles btn_SelectColor.Click

        Dim colors() As Color = _
            {Color.Red, Color.Green, Color.Blue}

        Using f2 As New Form2(colors)
            f2.ShowDialog()

            If Not f2.UserCancel Then
                If f2.UserSelection IsNot Nothing Then
                    MessageBox.Show("The user selected the color " & _
                                    f2.UserSelection.ToString)
                End If
            End If
        End Using

    End Sub
End Class

What I want you to recognize above is that I'm creating a NEW instance of Form2, I'm passing in the colors and Form2 is shown modally. At that point, Form1 waits; the rest of the code won't be executed yet -- not until Form2 is dismissed.

Given that, let's have a look at the code for Form2:

Public Class Form2
    Private _colorChoices As IEnumerable(Of Color)
    Private _userCancel As Boolean = True
    Private _userSelection As Nullable(Of Color)



    Public Sub New(ByVal colors As IEnumerable(Of Color))
        InitializeComponent()

        If colors Is Nothing OrElse colors.Count <> 3 Then
            Close()
        Else
            _colorChoices = colors
        End If

    End Sub



    Private Sub _
        Form2_Load(sender As System.Object, _
                   e As System.EventArgs) _
                   Handles MyBase.Load

        With Me
            .AcceptButton = btn_OK
            .CancelButton = btn_Cancel
        End With

        RadioButton1.Text = _colorChoices(0).ToString
        RadioButton2.Text = _colorChoices(1).ToString
        RadioButton3.Text = _colorChoices(2).ToString

    End Sub



    Private Sub _
        Form2_Shown(sender As Object, _
                    e As System.EventArgs) _
                    Handles Me.Shown

        RadioButton1.Checked = False
        RadioButton2.Checked = False
        RadioButton3.Checked = False

        btn_OK.Enabled = False

    End Sub

    Private Sub _
        CheckedChanged(sender As Object, _
                       e As System.EventArgs) Handles _
                       RadioButton1.CheckedChanged, _
                       RadioButton2.CheckedChanged, _
                       RadioButton3.CheckedChanged

        If RadioButton1.Checked Then
            _userSelection = _colorChoices(0)

        ElseIf RadioButton2.Checked Then
            _userSelection = _colorChoices(1)

        ElseIf RadioButton3.Checked Then
            _userSelection = _colorChoices(2)
        End If

        btn_OK.Enabled = True

    End Sub



    Private Sub _
        btn_OK_Click(sender As System.Object, _
                     e As System.EventArgs) _
                     Handles btn_OK.Click

        If _userSelection.HasValue Then
            _userCancel = False
            Close()
        End If

    End Sub



    Private Sub _
        btn_Cancel_Click(sender As System.Object, _
                         e As System.EventArgs) _
                         Handles btn_Cancel.Click

        Close()

    End Sub

    Public ReadOnly Property UserCancel As Boolean
        Get
            Return _userCancel
        End Get
    End Property



    Public ReadOnly Property UserSelection As Nullable(Of Color)
        Get
            Return _userSelection
        End Get
    End Property
End Class

A few things here: The colors to show the names of is being passed in as an IEnumerable(Of Color) -- that's an easy way that I can set it up to accept a generic List(Of Color), an array (of color), etc..

Also, the user's selection is a nullable type. I'm using that because a color is a structure (so it's a value type). By default it's null.

Now let's proceed and see what happens here:

In form1 I'll click the button:

That passes in the three colors and form2 is shown, displaying those colors and the three choices:

Note here that the "OK" button is disabled. I won't enable it until the user selects a color. Once they do, the fact that they're radiobuttons means that one will always be selected from that point on so I don't have to worry about that part.

I'll pick the middle one:

Now that I've chosen a color, the "OK" button is enabled. At any point they can "quit" but closing the form ("X") or clicking the cancel button but only when they click the "OK" will the returning boolean named "UserCancel" be true. That way I can be sure that I know whether they meant to cancel it or not.

Continuing now, I'll click the "OK" button there and code execution is returned to Form1 where it's instructed to show a messagebox:

Think that through and see if you can apply some of it to your own?

"A problem well stated is a problem half solved.” - Charles F. Kettering


Monday, November 27, 2017 8:49 PM

This is the rference:
"Unlike non-modal forms, the Close method is not called by the .NET Framework when the user clicks the close form button of a dialog box or sets the value of the DialogResult property."
https://msdn.microsoft.com/en-us/library/c7ykbedk%28v=vs.110%29.aspx

So the problem is not that the form is failing to close, it is failing to hide.  You need to look for something in the form that prevents it from hiding.  Or, dispose of the form after control returns to the calling form.

Hi Acmar.  As I understand the references you mention, that is not the problem I have having.  My second form absolutely closes when I click the DONE button (or the close of the dialog box).  The issue I have is that the form does not close when it encounters a “Me.Close()” in any other part of the code in the second form. I am trying to use Me.Close() in my code to immediately get out of the second form and back to the first form.


Monday, November 27, 2017 9:03 PM

Hi Cor.  I read what you wrote but I did not understand it and after this I still don't.

Hi TJBlues, I read what you wrote, but I do not understand it and after this I still don't, maybe better to tell what you did not understand. 

Your problem is so simple but many don't understand the way it is done in VB. That lies in the fact that currently the application framework in windows forms since version VB8 incorporates the Program module. 

That was to help VB6 programmers to make it easier, but that help had in fact reverse side effect. It does not exist in that way in other VB templates then Windows Forms and is in the other .Net programs completely not. 

Mainly try to look at what I wrote in my first message. And know that if you open a form with ShowDialog it is the same extras as with VB6.  If you click on the close button of that, it does return a dialog result of OK and that makes it even more confusing.

Success
Cor


Monday, November 27, 2017 9:14 PM

Me.Close does not have effect on form that is not displayed, and it does not prevent the form to be displayed when ImgPreviewForm.ShowDialog is called after ImgPreviewForm.LoadImgsInfoToArrays (inside unclear coverView.ShowDialog, for example).


Monday, November 27, 2017 10:12 PM

Me.Close does not have effect on form that is not displayed, and it does not prevent the form to be displayed when ImgPreviewForm.ShowDialog is called after ImgPreviewForm.LoadImgsInfoToArrays (inside unclear coverView.ShowDialog, for example).

Sorry Viorel, 

I really don't understand what you write. 

It is so simple, try this code. Simply 2 forms and one button. Direct done using VB and not first C# and then convert.

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Hide()
        Using DubForm As New Form2
            If DubForm.ShowDialog <> DialogResult.Cancel Then
                Close()
            Else
                Show()
            End If
        End Using
    End Sub
End Class
Public Class Form2
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        DialogResult = DialogResult.Cancel
    End Sub
End Class

Success
Cor


Wednesday, November 29, 2017 3:41 PM

I made a sample, new project with 2 forms.

Form1 Code:

Public Class Form1
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Using F2 As New Form2
            F2.ShowDialog()
        End Using
    End Sub
End Class

Form2 Code:

Public Class Form2
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim Numerator As Decimal
        Dim Denominator As Decimal
        Dim Result As Decimal
        Try
            Numerator = CDec(TextBox1.Text)
            Denominator = CDec(TextBox2.Text)
            Result = Numerator / Denominator
            TextBox3.Text = Result.ToString
        Catch ex As Exception
            MessageBox.Show("Division Error" & vbNewLine & ex.Message)
            Me.Close()
        End Try
    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        Me.Close()
    End Sub
End Class

Once Form2 is open, if you leave either Numerator or Denominator Blank, or enter something that's not a number, or 0 for Denominator, the program shows an error message and closes. 


Wednesday, November 29, 2017 6:34 PM

Frank.  Thanks very much for your help and the time you spent building this simplified version of a dual form project.  It helped me immensely.

I'm glad that it helped.

There's nothing like stepping into the code and watching what does what.

:)

"A problem well stated is a problem half solved.” - Charles F. Kettering