Form being disposed of randomly
Protected Overrides Sub LoadForm() MyBase.LoadForm() Try 'StartProcess might be causing an error (error msg is issue with loading config, which would be incorrect) StartProcess() Dim D As New _Delegate(AddressOf SOPERATION) Me.Invoke(D) BusinessObject = New bConfig(Me) CType(BusinessObject, bConfig).LoadKeyValue() Catch ex As Exception MESSAGES.ShowMessage(MessageIndex.ErrInLoadConfigData, TitleIndex.LoadForm, MessageBoxButtons.OK, MessageBoxIcon.Information) StopProcess() EnableDisable(CurrentBillType) End Try End Sub
I can run this 100 times under the exact same conditions and it seems like 40 times it will crash with the following error:
"Cannot access a disposed object. Object name: 'frmImportExport'."
It will either die on
'within StartProcess() Dim __Delegate As New _Delegate(AddressOf StartProcess) Me.Invoke(__Delegate)
Dim D As New _Delegate(AddressOf SOPERATION)
I know it's difficult to answer without seeing the entire code, but I cannot for the life of me figure out why this sometimes does and sometimes does not work under the same conditions. Any ideas about what I could look for? The forum isn't being disposed manually anywhere that I see, and this code is being executed on formload.
StackTrace: "at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object args, Boolean synchronous) at System.Windows.Forms.Control.Invoke(Delegate method, Object args) at ShiftBilling.BaseForm.StartProcess() in C:\Users....\BaseForm.vb:line 138 at ShiftBilling.frmImportExport.LoadForm() in C:\Users\Alec\Work\Levelset\ShiftBillingSource\ShiftBilling_Source\JLRBilling\frmImportExport.vb:line 66" String
The contents of ShowProcess() aren't really important, but here's the code in it:
Protected Sub StartProcess() If Me.InvokeRequired Then Dim __Delegate As New _Delegate(AddressOf StartProcess) Me.Invoke(__Delegate) Else Validator.Clear() 'If Me.MdiParent IsNot Nothing Then IsProcessRunning = True frmMain.ShowProgress() 'CType(Me.MdiParent, frmMain).ShowProgress() EnableControls(False) 'End If End If End Sub
It never reaches EndProcess if it fails, so there's no real need for the code.
Here is the code that is executed when the link is clicked to display the form:
Private Sub ImportExportMenu_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ImportExportMenu.Click _frmimport = New frmImportExport If clickWindow(_frmimport.Text, _frmimport) = True Then Exit Sub _frmimport.Show() _frmimport.MdiParent = Me SetFormPosition(_frmimport) End Sub
It's a subform that is to be displayed within a main form.
It may also be worth noting that this was an outsourced project that I've only had a day and a half to work with.
_frmimport.Show() _frmimport.MdiParent = Me
That could be part of your problem. The Show() method forces the Windows window to be created, the Handle property gets a value. You then change the MdiParent property, which requires an entirely different kind of window, an MDI child. Which requires Winforms to destroy the Windows window and recreate it. The Handle value changes. Meanwhile, you've started a thread that is using the form's InvokeRequired and Invoke members. Which require the Handle property to be valid. It's a matter of timing whether or not that's going to blow.
Swap the two statements.
It will be much easier to answer if you post some more information. In particular:
- The stack trace of the exception you get.
- More code of your Form class, especially the StartProcess and EndProcess methods.
- How are you showing your Form? Do you use Application.Run or Form.ShowDialog?
Here's an idea:
Override Dispose on your Form, and in it do something like Debugger.Break();. Now run your app again 100 times until you find out why your Form is being disposed. Post the stack trrce showing the call to Dispose.
It would have been easier to figure out if you would say you manually close the window when the problem happens... :)
Anyway, this behavior is by design. In .NET, when a Form is created using Form.Show, when the Form closes, Dispose is called automatically.
But this should not be a problem for you. You don't really need to marshal the call to StartProcess to the UI thread, because you are alread on the UI thread.
And if you do for some reason want to marshal StartProcess from a background thread to the UI thread, simply call Invoke on the main window instead of on the FrmImportExport instance that may be closed.
Based on the information provided it seems your LoadForm is occuring on the UI Thread. If this is the case why you are using Me.Invoke()? If you are on the UI thread it will immediately execute StartProcess(). It also looks like you are invoking StartProcess within itself? Which will result in a recursion. Something seems amiss with the code you've provided. I agree with the others we need to see some additional code.
The error "Cannot access a disposed object. Object name: 'frmImportExport'." means that the GC has collected the frmImportExport, it was not reachable. It appears from your code that you're storing it in _frmimport, but where that is stored is not shown. Perhaps its stored in a temporary location? Making that variable shared might help.