I apologize if this is a simple question (my Google-Fu may be bad today).
Imagine this WinForms application, that has this type of design: Main application -> shows
Yes, the default handling of Application.ThreadException was a mistake. Unfortunately, it was a necessary mistake, needed to not immediately discourage and despair hundreds of thousands of programmers writing their first Windows Forms application.
The fix you are contemplating is not a fix, it has a lot of potential to make it worse. While a user clicking the Continue button on the exception dialog is a questionable outcome, swallowing exceptions in a global exception handler is much worse.
Yes, do write a replacement handler for ThreadException. Have it display the value of e.Exception.ToString() in a message box so the user has some idea what blew up. Then fire off an email or append to an error log so you know what went wrong. Then call Environment.FailFast() so no more damage can be done.
Do the same for AppDomain.CurrentDomain.UnhandledException. It won't get much of a workout.
Use the feedback to improve your code. You'll find out where validation is required. You can help the customer's IT staff diagnose trouble with their LAN and equipment. And you'll find the very few cases where your own try/catch blocks might be able to recover from the exception.
Sounds like you want aspects. PostSharp could help you out.
You may be able to use the AppDomain.CurrentDomain.UnhandledException handler to intercept the errors on the main UI thread and handle them per-dialog. From MSDN:
In applications that use Windows Forms, unhandled exceptions in the main application thread cause the
Application.ThreadException
event to be raised. If this event is handled, the default behavior is that the unhandled exception does not terminate the application, although the application is left in an unknown state. In that case, theUnhandledException
event is not raised. This behavior can be changed by using the application configuration file, or by using theApplication.SetUnhandledExceptionMode
method to change the mode toUnhandledExceptionMode.ThrowException
before theThreadException
event handler is hooked up. This applies only to the main application thread. TheUnhandledException
event is raised for unhandled exceptions thrown in other threads.
Global exception handling in WinForms application is done using two handlers: Application.ThreadException and AppDomain.CurrentDomain.UnhandledException. ThreadException catches unhandled exceptions in the main application thread, while CurrentDomain.UnhandledException catches unhandled exceptions in all other threads. Global exception handling may be used for the following purposes: showing user-friendly error message, logging the stack trace and other useful information, cleanup, sending error report to developer. After unhandled exception is catched, application should be terminated. You may want to restart it, but it is impossible to correct an error and continue, at least, in non-trivial applications.
Global exception handling is not replacement for local exception handling, which still should be used. Local exception handlers should never use catch Exception, because this effectively hides programming bugs. It is necessary to catch only expected exceptions in every case. Any unexpected exception should crash the program.
You may like to rethink the design of your application slightly if you're doing stuff in combobox event handlers that might throw exceptions.
An alternative would be to initialise the dialog with all the information it needs before showing it to the user. The user then makes selections, and presses OK, and then the parent dialog could process the information in the dialog.
The exception handling could then be done in the parent dialog.
Of course this wouldn't be appropriate if you need to dynamically update the data in the dialog based on user actions...
e.g.
MyDialog myDialog = new MyDialog();
myDialog.Init(//data for the user to choose/manipulate);
if(myDialog.ShowDialog() == DialogResult.OK)
{
try{
ProcessDialogData(myDialog.SomeDataObject);
}
catch(/*...*/}
}
HTH