Introduction
Exceptions are inevitable, so they might as well look good. Just
calling MessageBox.Show(ex.ToString())
doesn't cut it for me. I prefer something that not only looks better than that, but also makes it easy for users
to report all the information about an exception.
This article presents the ExceptionViewer
class. Similar to Microsoft's ExceptionMessageBox
, it's designed for displaying an exception, its nested inner
exceptions, and all their properties (using reflection). The source code download is a Visual Studio 2008 solution.
Background
For years, I used the ExceptionMessageBox
class contained in Microsoft.ExceptionMessageBox.dll to display my exceptions. However, I was never comfortable
redistributing that DLL with my applications. Also, users never seemed to realize they could access more details about the exceptions and copy those
details into emails and bug reports. Finally, I'm using WPF now and ExceptionMessageBox
just doesn't look like it's part of a WPF app.
The ExceptionViewer
class in this article address those issues. It's simply a WPF window class you can add directly to your application (not requiring
a separate DLL). The "Copy All To Clipboard" button is highly visible so users are more likely to use it.
Using the Code
To display an exception, just construct an instance and call ShowDialog()
.
try
{
}
catch (Exception ex)
{
ExceptionViewer ev = new ExceptionViewer("An unexpected error occurred in the application.", ex, this);
ev.ShowDialog();
}
The last parameter to the constructor is optional. It specifies the Owner
window. If specified, ExceptionViewer
will set its own
Style
property to the Owner.Style
and set WindowStartupLocation
to WindowStartupLocation.CenterOwner
.
Of course, you can override these properties before calling ShowDialog()
.
The default title of the window is "Error - <ProductName>", where <ProductName> is taken from the AssemblyProduct
attribute of the
application (specified in ApplicationInfo.cs). You can change this by setting the static property DefaultTitle
, or setting the instance property Title
before calling ShowDialog()
.
Another static property, DefaultPaneBrush
, specifies the Brush
used for backgrounds of the two panes. It is null by default.
User Experience
The first screen shot (at the top of the article) is how the window first appears to the user. There's a splitter between the two panes, positioned so all of
the left pane's content is visible without scrolling. The "All Messages" node is selected, which displays whatever header message is passed to the constructor in bold,
followed by the "outer" exception message, it's InnerException
message, and so on.
The following screen shot is how it looks when one of the exceptions is selected and "Wrap text" is unchecked. All of the exception's properties are displayed in the right pane, using the
exception's type as the header. Note that the key/value pairs of the Data
property, if any, are enumerated.
You can also expand an exception in the tree and view each property individually.
The "Copy All To Clipboard" button copies all of the information including the "header" message to the clipboard. Both Rich Text and Plain Text formats are placed
on the clipboard so the "best" format is used when pasting.