Thursday, February 15, 2018

WPF program "Has stopped working"


Recently I started getting a slew of these errors being reported by my QA group for an existing Accounts Payable project. It turned out that my boss had commented out the unhandled exception handlers for the project. The original designer of the project didn't really understand exception handling so he relied on the unhandled exception handler a lot.

Let's create a project that throws an unhandled exception, then we'll see how to handle them. Create a new C# WPF application called UnhandledExceptions. Target any framework you want.


The main window will have a single button. When the user clicks on it we will attempt to add to an uninitialized list which will throw an exception. As we have no exception handling, we will see the dialog at the top of this blog entry.

The XAML and code behind look like this...

<Window x:Class="UnhandledExceptions.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:UnhandledExceptions"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="Click Me" Click="Button_Click"/>
    </Grid>
</Window>


and

using System;
using System.Collections.Generic;
using System.Windows;

namespace UnhandledExceptions
{
    public partial class MainWindow : Window
    {
        List<String> l = null;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            l.Add("A");
        }
    }
}

If you run this in visual studio you will find that visual studio is very helpful and displays the exception on the line that throws it, but the user will not have such a pleasant experience. Build the project and then browse to the executable and run it. Mine is found at C:\Users\me\Documents\Visual Studio 2015\Projects\UnhandledExceptions\UnhandledExceptions\bin\Debug\UnhandledExceptions.exe.



Fortunately this is an easy fix.

In MainWindow, add an unhandled exception handler and then write the code for the handler. I have chosen to use the exception's ToString method and flag the event as handled, so the default dialog box does not get shown. You can also opt to terminate the application here if you want. The code behind now looks like this.

using System;
using System.Collections.Generic;
using System.Windows;

namespace UnhandledExceptions
{
    public partial class MainWindow : Window
    {
        List<String> l = null;

        public MainWindow()
        {
            InitializeComponent();
            Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
        }

        private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.ToString());
            Application.Current.Shutdown();
            e.Handled = true;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            l.Add("A");
        }
    }
}

Build the project again and run the executable from Windows Explorer.