vb.net cannot access a disposed object when opening form - vb.net

I have a program that we use to run different reports. Based on the menu option chosen, I open the same form that lists the reports based on the menu option.
(There are also different options and functionalities in the program, not just one form).
When clicking a menu option, I have the following bit of code
Private Sub ReportsToolStripMenuItem1_Click(sender As Object, e As EventArgs) Handles ReportsToolStripMenuItem1.Click
FormLocation = "F_Legal"
FormName = "Legal"
PrepareForm(F_Select_Report)
End Sub 'ReportsToolStripMenuItem1_Click
Where F_Select_Report the form is that is opened.
Private Sub PrepareForm(formName As Form)
Cursor = Cursors.WaitCursor
For Each Form In Me.MdiChildren
Form.Close()
Next
formName.MdiParent = Me
formName.Height = Me.Height
formName.Width = Me.Width
formName.Show()
Cursor = Cursors.Arrow
End Sub 'PrepareForm
This bit is called, closing all other opened forms, and then open the form that is called.
This works fine on the first time I try and open a form, but on the second try, I get an error message saying
Cannot access a disposed object.
And then on the third try, it opens the form again.
How would I fix this up?
Thanks a lot

Form.Close implicitly calls Form.Dispose
So if the formName is an MdiChild it gets disposed in the For Each loop.
Then, on the next line your code attempts to assign to its MdiParent property and there the error occurs.
So you need to skip it when closing MDI children like this:
For Each Form In Me.MdiChildren
If Not Form Is formName Then Form.Close
Next
Given your code I think it is better to close the children before showing the F_Select_Report form. I.e. move the For Each loop as is to the top of the ReportsToolStripMenuItem1_Click handler.

Not sure if it is the best/nicest solution, but found a solution to this.
Instead of 1 Sub that does both closes all open forms, and then opens the new one, I split it out over 2 Subs.
Close all open ones
Private Sub CloseAllForms()
For Each Form In Me.MdiChildren
Form.Close()
Next
End Sub 'CloseAllForms
And then open the new form
Private Sub PrepareForm(formName As Form)
Cursor = Cursors.WaitCursor
Try
formName.MdiParent = Me
formName.Height = Me.Height
formName.Width = Me.Width
formName.Show()
Catch ex As Exception
MessageBox.Show("Error: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
Cursor = Cursors.Arrow
End Sub 'PrepareForm
Now it works as needed.

Related

Parent form sometimes does not close (Only in Windows 10)

My main form is frmInvoice. This sub is located inside frmInvoice.
This is one of the Subs that sometimes causes frmDark to not close. frmLookup does not display when this happens. frmDark just stays there covering frmInvoice. It's like it doesn't reach the call to frm.ShowDialog(frmDark), cause when I press the lookup key, it displays the frmLookup, but upon closing frmLookup, frmDark is still there.
No exception is being raised.
Note that this only happens in Windows 10. In Windows 8/7, this never happened. What am I missing?
This happens at different times. Sometimes I could press the lookup key for 20 times and it will display fine. Sometimes, after 1 press of the lookup key and this happens.
Private Sub ItemLookup()
Try
Using frmDark As New Form
With frmDark
.ShowInTaskbar = False
.Icon = Me.Icon
.FormBorderStyle = Windows.Forms.FormBorderStyle.None
.BackColor = Color.Black
.Opacity = 0.95
.WindowState = FormWindowState.Maximized
.Show(Me)
Using frm As New frmLookup
With frm
.Icon = Me.Icon
.ShowDialog(frmDark)
frmDark.Close()
If .DialogResult = Windows.Forms.DialogResult.OK Then
' Do stuff here
End If
End With
End Using
End With
End Using
Catch ex As Exception
ErrMsg(ex)
End Try
End Sub
UPDATE: I'm using .Net Framework 4.8
Thanks
I would suggest rearranging the code like so:
Dim lookupResult As DialogResult
Using frmDark As New Form With {.ShowInTaskbar = False,
.Icon = Me.Icon,
...}
frmDark.Show(Me)
Using frm As New frmLookup With {.Icon = Me.Icon}
lookupResult = frm.ShowDialog(frmDark)
End Using
End Using
If lookupResult = DialogResult.OK Then
'...
End If
Because that code exits the Using block that created frmDark, there should be no way that it can't close.
Also, instead of using a vanilla Form and configuring it on demand, I would suggest that you create a dedicated form type to use as the overlay in that scenario. You can then get rid of all the property assignments.
Having a dedicated overlay form would also allow you to reconfigure things significantly and, in my opinion, better. The overlay form could have a property of type Form. You main form could then create a frmLookup instance and assign it to that property, than call ShowDialog on the overlay form. In the Shown event handler of the overlay form, it could then call ShowDialog on the form in that property. When that call returns, it could assign the result to its own DialogResult property and close itself. The main form would then just get the result from calling ShowDialog on the overlay. That might look like this:
Public Class OverlayForm
Public Property DialogueForm As Form
Private Sub OverlayForm_Shown(sender As Object, e As EventArgs) Handles Me.Shown
DialogResult = DialogueForm.ShowDialog()
End Sub
End Class
and this:
Public Class MainForm
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Using dialogue As New DialogueForm,
overlay As New OverlayForm With {.DialogueForm = dialogue}
If overlay.ShowDialog() = DialogResult.OK Then
MessageBox.Show("OK")
End If
End Using
End Sub
End Class

Why MDI form children reorder after closing last child?

I have a windows forms application project in VB with a MdiContainer called "FMenuMdiParent" and I show every form child this way:
With form1
.MdiParent = FMenuMdiParent
.Show()
End With
All works fine but when I have more than 2 forms and close any of them the first form always get focus and I need they respect the order one each other.
I tried with the next code and it works. But now I can't swap the focus between forms:
Private Sub FMenu_MdiChildActivate(sender As Object, e As EventArgs) Handles MyBase.MdiChildActivate
Try
Me.MdiChildren(Me.MdiChildren.Length - 1).Activate()
Catch ex As Exception
LogError.RegistrarErrorEF(SYS, FORM_PAGINA, Reflection.MethodBase.GetCurrentMethod().Name, ex.Message, Sesion.Login, Programador.Juan_Erroa)
End Try
End Sub

Working with passed data between forms

Currently in my windows form, I have a few WinForms to work with. One WinForm acts as a main menu and is supposed to call another form as a secondary window on its own.
Private Sub btnMainGame_Click(sender As Object, e As EventArgs) Handles btnMainGame.Click
' This is the button to call up the main game controller. So simply hide this form aned then open the new form.
Dim frmController As New frmControllerScreen
frmController.Show()
Me.Hide() ' Happens on .Close as well
End Sub
The above code invokes another WinForm which is used to handle more options. When the user clicks on a particular button, a sub form is created again.
Dim OpenNewGameWindow As New frmGameConfig
OpenNewGameWindow.ShowDialog(Me)
Me.DialogResult = DialogResult.None ' Used to prevent the subform from closing the main form when it catches a dialog result.
Now in the frmGameConfig, the program is supposed to take data and pass it back to the form that called it.
Private Sub btnNewGameStartGame_Click(sender As Object, e As EventArgs) Handles btnNewGameStartGame.Click
' ... Skipped code...
frmControllerScreen.MasterQuestionList = QuestionList
frmControllerScreen.blnBankedTime = cbBankedTime.Checked
' ... Skipped code...
End Sub
However, when the frmController tries to reference MasterQuestionList... it returns a nullreference error as if it was not set.
Here's where things get funny...
When I made this code, frmControllerScreen was actually the startup form. Now when I change this form back to frmMainMenu, I get NullReference errors constantly.
My question: How am I supposed to pass information from one form to the next form if it was instantiated from a parent form. (Note I even moved the declartion to Public as a "module-wide" variable... and nothing happens but the same result.) The same error happens even if I go ahead and declare frmController.MasterQuestionList as well.
Instead of trying to pass data back from the called form to the caller, you can reference the called form's controls from the calling code after .ShowDialog.
Dim OpenNewGameWindow As New frmGameConfig
If OpenNewGameWindow.ShowDialog() Then
MasterQuestionList = OpenNewGameWindow.QuestionList
blnBankedTime = OpenNewGameWindow.cbBankedTime.Checked
End If
In OpenGameWindow button click:
Private Sub btnNewGameStartGame_Click(sender As Object, e As EventArgs) Handles btnNewGameStartGame.Click
Me.DialogResult = True
End Sub

VB.NET Calling forms by Variable

I'm playing around in vb.net and would like to create a menu for my application. The application has an Main which is the MDI Parent and then has the sub forms that open up as the user browses the menu structure. I would like to track which form the user came from so that when they close their current form, it opens up the previous form they had open.
What I have so far is a public variable "FormTracking" which is a list of Form. The open form function works fine, but when they close the form and it calls the "OpenPreviousForm" function it fails as the previous form has been closed/disposed. How can i create a new instance of the form as calling "NEW" doesn't seem to work
Public FormTracking As New List(Of Form)
Public Sub OpenForm(theNewForm As Object)
'First Declare the new form
Dim f As Form = DirectCast(theNewForm, Form)
'Set the Forms parent
f.MdiParent = frmMain2
'Add the form to the tracking
FormTracking.Add(theNewForm)
'Show the form
f.Show()
End Sub
Public Sub OpenPreviousForm()
If modMenu.FormTracking.Count > 1 Then
Dim f As New Form
f = modMenu.FormTracking(modMenu.FormTracking.Count - 2)
'Set the Forms parent
f.MdiParent = frmMain2
'Remove the last item
modMenu.FormTracking.RemoveAt(modMenu.FormTracking.Count - 1)
'Show the form
f.Show()
Else
MessageBox.Show("Whoops, run out of forms.... ", "modMenu - OpenPreviousForm")
End If
End Sub
When opening a form it it calls:
modMenu.OpenForm(menupage_1)
me.close
And when closing a form, i try to call
modMenu.OpenPreviousForm()
The error i am getting when calling the above code is
"An unhandled exception of type 'System.ObjectDisposedExeption' occured in System.Windows.Forms.dll
Additional Information: Cannot access a disposed object
I understand i need to create the object again, but not sure how to using the functionality as above. Alternatively, if someone can present a better way of doing an application menu, please feel free to let me know.
Cheers
Use Me.Hide instead of Me.Close so you do not dispose the form.

Forms acting unexpectedly

I'll try to explain this best I can.
I have windows form application that contaions numerous forms. The first form
to open is a non modal form that acts as command form to issue various formats to
the underlying reservation program. A second form also opens which is basically my
Main form for the application. This form contains multiple check boxes to run methods
that make changes to the reservation program. This form is also modeless. Each box that
is checked runs concurrently and performs methods to delete, change and add to the
res program below. Various boxes may be checked at any given time. Below is code to
handle the checkboxes:
Private Sub frmOWTMain_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp
If e.KeyCode = Keys.Enter Then
Me.Hide() 'here i want to hide the OWTMain form
Call ckforPNR()
If Me.cbPricing.Checked Then
Call doPricing()
Me.cbPricing.Checked = false
End If
If Me.cbUdids.Checked Then
frmUdids.Show()
Me.cbUdids.Checked = False
End If
If Me.cbMod.Checked Then
Call doModUdids()
End If
If Me.cbFare.Checked Then
Call doFareSavings()
Me.cbFare.Checked = False
End If
End If
Me.show() 'This is the problem. This runs during method calls. All I'm
'looking to do is re display the OWTMain form.
End Sub
At this point I would want to re display the OWTMain form above. This is
where I am having an issue. As you can see, a number of methods are called
which involve showing other forms to the user. I do NOT want any of these
forms to be modal because I want the original first opened form to still be
able to issue commands to the res program toview information needed by the other forms.
Here is an example of some of the method calls:
Private Sub doPricing()
Dim myPrice As New Pricing 'a call to another class that handles pricing
If myPrice.getTQT = False Then
frmAddPricing.ShowDialog() 'showing new forms
Else
frmCurPricing.ShowDialog()
End If
End Sub
Private Sub doFareSavings()
Dim myPrice As New Pricing
If myPrice.checkForFS = False Then
frmFS.ShowDialog() 'showing new forms
End If
If myPrice.checkForFS = True Then
frmFSVerify.ShowDialog()
End If
End Sub
When I call any of these methods the form OWTMain shows prematurely while other
forms from the called method are still running. I expected the code at the top to run
in order of the calls but that is not the case. I just want to re display the OWTMain
form after all the code is run. I have not been able to figure this out without
creating a ton of code to minipulate the opening and closing of the windows.
Any help with this would be greatly appreciated. Thank you.
John
This will check if all sub forms are closed and then re-show the main form.
remove the exitsing me.show()
Public Sub ReShowMainForm()
' add all sub forms to this check
if frmFS.Visible = false andalso
frmUdids.Visible = false andalso
frmFSVerify.Visble = false then
Me.Show
End If
End Sub
change xyzForm.Show to xyzForm.Show(me) to make the main form available as parent to the sub forms.
Handle the FormClosed event in each sub form and add the following code
DirectCast( me.parent, frmOWTMain).ReShowMainForm()