13
votes

A WPF window dialog is shown using the ShowDialog method in the Window class like when a button is pressed on the main window, like this.

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var window = new Window1();
                window.ShowDialog();
            }
            catch (ApplicationException ex)
            {
                MessageBox.Show("I am not shown.");
            }
        }

The window has a Loaded event subscribed in the xaml like this:

<Window x:Class="Stackoverflow.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Loaded="Window_Loaded">
    <Grid />
</Window>

An exception is thrown in the Window_Loaded event

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        throw new ApplicationException();
    }

However the exception is not catched by the catch around the ShowDialog call, nor does the call return. The exception is swallowed and the window still displayed.

Why does this happen and how would I go about handling an exception in the Window_Loaded event of a WPF window? Do I have to catch it in the event-handler and Dispose the window manually?

In WinForms you need to call Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)

in order to let exceptions bubble through ShowDialog calls. Is there a similar switch that needs to be set on WPF?

5
I tried to reproduce your situation, but with no success. Exceptions are caught in usual manner. I suppose, you've simplfied code, but it appears that main point is in details. Provide them and I'll try to help.Alex Zhevzhik
Thanks for trying to reproduce. I've reproduced the problem in a very simple exemple from where I took the posted source code. Im using VS2010. I'll edit my question and add some relevant information for reproducing.vidstige

5 Answers

7
votes

I've only seen this issue on x64 machines, with code compiled with Any Cpu. Changing your program to compile as x84 may fix it, but I've had problems there myself depending on our assemblies.
My only code suggestion is the following, and even then it's not guaranteed to pick it up. Catch the exception, and re-throw it in a Background worker.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    try
    {
        /// your code here...
        throw new ApplicationException();
        /// your code here...
    }
    catch (Exception ex)
    {
        if (IntPtr.Size == 8)   // 64bit machines are unable to properly throw the errors during a Page_Loaded event.
        {
            BackgroundWorker loaderExceptionWorker = new BackgroundWorker();
            loaderExceptionWorker.DoWork += ((exceptionWorkerSender, runWorkerCompletedEventArgs) => { runWorkerCompletedEventArgs.Result = runWorkerCompletedEventArgs.Argument; });
            loaderExceptionWorker.RunWorkerCompleted += ((exceptionWorkerSender, runWorkerCompletedEventArgs) => { throw (Exception)runWorkerCompletedEventArgs.Result; });
            loaderExceptionWorker.RunWorkerAsync(ex);
        }
        else
            throw;
    }
}
2
votes

The "Why" is explained here: http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/

In short, the exception cannot be propagated in 64-bit operating systems because there is a transition between user and kernel mode.

The test of IntPtr.Size in @midspace answer is not adequate because IntPtr.Size will be equal to 4 in an x86 process running on a x64 os (you need to use Environment.Is64BitOperatingSystem instead on .NET 4 and greater).

The solution now: use another event like ContentRendered which is called after the Loaded one or put your code in the window constructor.

Never use Loaded (or OnLoad in Winforms), because if there is an exception there, you don't know what can happens.

Have a look also at this answer: https://stackoverflow.com/a/4934010/200443

1
votes

I also reconstructed your answer in Visual Studio 2010 in a blank WPF 3.5 project.

The project behaved as expected, i.e. the Window_Loaded threw the exception, and it was caught by the button click event.

So I'm not sure why yours isn't working, maybe try posting your App.xml.cs and any other code you haven't shown here?

In the meantime, I thought I would point out a few things:

WPF does indeed handle "uncaught" exceptions a little differently from WinForms. Try looking at this for a starter:

http://msdn2.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx

It looks as if there isn't an exact equivalent in WPF for the SetUnhandledExceptionMode method (See http://social.msdn.microsoft.com/forums/en-US/wpf/thread/955c75f8-9cd9-4158-bed9-544bd7946413). Try their advice about registering a handler and see if that helps you?

I would recommend stepping through your code - set a breakpoint in the Window_Loaded, and see what happens - pay careful attention to the call stack.

Good luck!

1
votes

Researching this a bit more I found this peculiar blogg entry describing a similar problem.

http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/

As it turns out it might be a 64-bit processor architecture problem. Who would have guessed?! It might explain why some people could not reproduce the issue my simple example. I tried to compile my example in "Any CPU", x64 and x86 but to no avail. On x64 the whole thing actually blew up completely crashing with a windows crash dialog.

So I guess this is the answer without verifying it on a 32-bit machine.

0
votes

I've had similar problem, and trying to understand where it's coming is frustrating. There's a couple of things that could be causing a problem.

  • Are you calling anything before the method call InitializeComponent(); ? Previously I've had a method calling xaml elements, which haven't been initialised yet.
  • Have you tried pressing F10 to start the application, using Step Over will let you see the exact process start up?
  • Have you checked your naming? XAML can swallow errors such as methods being mis-spelt, and then an exception is thrown on run time, this particularly true DataSet providers. You'd be surprised what you can get away with.
  • Catching an exception for opening a form is pretty fundamental, I'd rather look at any dependents (Data or XAML bindings) and deal with those first.

Hope those points help.......