0

I have experienced the following. In a large application that shows an MDI child form an exception in the child form does also close the parent form.

I am trying to catch the exception and show an error message in a special error form. The desired behavior would be to catch the exception without the parent form being disposed. In the child form I have a button that triggers an exception

 throw new ApplicationException("test");

If I put a breakpoint into the main form (the MDI parent) Dispose method

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        if (components != null)
        {
            components.Dispose();
        }
    }
    base.Dispose(disposing);
}

I get the following call-stack

myApp.dll!myForm.Dispose(bool disposing)
System.dll!System.ComponentModel.Component.Dispose()
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadWindows.Dispose()
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.DisposeThreadWindows()
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.Dispose(bool postQuit)
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reasion, System.Windows.Forms.ApplicationContext context)
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reasion, System.Windows.Forms.ApplicationContext context)
System.Windows.Forms.dll!System.Windows.Forms.Application.Run()

with disposing being true.

Afterwards the exception I want to catch is indeed caught as expected in a top level try-catch statement but then the mdi parent form is already closed (why?).


Here some code showing how my top level try-catch works:

public class MainApplication
{
    [STAThread]
    static void Main(string[] args)
    {
        Application.ThreadException += MyThreadExceptionHandler;
        try
        {
            OurMain(args);
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.Message + "\n" + ex.StackTrace, "Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
        }
    }

    private static void MyThreadExceptionHandler(object sender, ThreadExceptionEventArgs e)
    {
        MessageBox.Show(e.Exception.Message + "\n" + e.Exception.StackTrace, "Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
    }

    private static void OurMain(string[] args) 
    {
        //run the application
    }

}

With my question here I am looking for strategies to resolve the issue and learn why the MDI parent form is closing (and finally prevent it from closing).

What I think I know so far:

  • I guess it is not a threading issue (btw. I do also handle the ThreadException event and get nothing there) because I can catch the exception in the UI thread.

Note: I have asked the question in a very general way. Please tell me what specifics information would be relevant for you to be able to answer the question.


Solution in my specific case:

In my case the solution was to not only handle Application.ThreadException but also use other option like described in this answer. In my case handling Dispatcher.CurrentDispatcher.UnhandledException did the job. Application.ThreadException seems only work for pure WinForms but I had encapsulated a Web View and the binding to the Web View triggered the exception and the Application.ThreadException did not react on that.

Community
  • 1
  • 1
Sjoerd222888
  • 3,228
  • 3
  • 31
  • 64
  • In `program.cs`, wire up the [Application.ThreadException](https://msdn.microsoft.com/en-us/library/system.windows.forms.application.threadexception(v=vs.110).aspx) Event and take action from there... – Idle_Mind Sep 07 '15 at 16:28
  • @Idle_Mind: As can be read in the question I handle this Event... – Sjoerd222888 Sep 07 '15 at 16:29
  • Apologies...you have: _afterwards the exception I want to catch is indeed caught as expected on a top level try-catch statement but then the main form is already removed._ Where is this try/catch at? Can you show that code? – Idle_Mind Sep 07 '15 at 16:33
  • 1
    Just did a simple test, **with no try/catch blocks**, and my MdiParent form did not close when the exception was thrown. The exception was then trapped in the Application.ThreadException event where I was able to display an error form. – Idle_Mind Sep 07 '15 at 16:39
  • I have edited my question, maybe it was not clear enough. – Sjoerd222888 Sep 08 '15 at 07:57

1 Answers1

0

When an error occurs, the exception will "bubble up" the code hierarchy until it is either caught (with a Try/Catch) or it reaches the top.

When it reaches the top (in debug) the application simply closes down - closing any open forms.

If you run the .exe you will see the standard message: "Unhandled exception has occurred in your application." with Continue/Quit buttons.

The way to handle this is using Try/Catch blocks to catch anticipated errors.


For the exception to get to your top level main function it will have already bubbled-up past your form causing the form to be disposed (as the form object is no longer in scope). The form is either disposed of by the form instantiation code or by the garbage collector. This is all part of the automated clean-up of memory.

Ulric
  • 826
  • 5
  • 16
  • please read the question before you post an answer... While the statements are all correct I do not see a relation to the question (except that both contain the word 'exception'). – Sjoerd222888 Sep 07 '15 at 16:25
  • @ Sjoerd: This was the question: _"I am looking for strategies to resolve the issue and learn why the form is closing (and finally prevent it from closing)._ My answer is completely relevant to the question. If it is unclear then I can elaborate. – Ulric Sep 07 '15 at 16:33
  • I have edited my question, maybe it was not clear enough. – Sjoerd222888 Sep 08 '15 at 07:53
  • _before the exception bubbled up to my top level main function the MDI parent form is already closed._ For the exception to get to your top level main function it will have already bubbled-up passed your form causing the form to be disposed (as the form object is no longer in scope). The form is either disposed of by the form instantiation code or by the garbage collector. This is all part of the automated clean-up of memory. – Ulric Sep 08 '15 at 09:05
  • Yes, that is true. The only strange thing is why I do not end up in the So my next question would be why I do not end up in the ThreadException event....Whatever: If you add your comment to the answer I will accept the answer. – Sjoerd222888 Sep 08 '15 at 15:05