none
Catch DispatcherUnhandledException from other Thread

    Question

  • Hi,

     

    I’m having trouble to catch the DispatcherUnhandledException from other threads than the 'main thread'. If you read the MSDN documentation  about the DispatcherUnhandledException it says:

     

     

    DispatcherUnhandledException is raised by an Application for each exception that is not handled within the AppDomain that the Application object was created in.

     

    The DispatcherUnhandledException event handler is passed a DispatcherUnhandledExceptionEventArgs argument that contains contextual information regarding the exception, including:

    • The exception (Exception).
    • The Dispatcher from which it originated (Dispatcher).

     

    This means that the exception also should be called from other threads than the main thread.

     

    If this isn't working, what's then the best way to handle global exceptions in WPF applications?

     

    Note, it works fine to catch the AppDomain.UnhandledException. But then its to late to handle the exception and the application is shut down.

     

     

    An example, raising exception from ThreadPool and from main the thread: 

    using System;

    using System.Windows;

    using System.Collections.Generic;

    using System.Text;

    using System.Windows.Threading;

    using System.Threading;

    namespace DispatcherUnhandledExceptionApplication

    {

    public class MyApplication : Application

    {

    [STAThread]

    public static void Main()

    {

    MyApplication app = new MyApplication();

    app.InitializeComponent();

    app.Run();

    }

    protected override void OnStartup(StartupEventArgs e)

    {

    base.OnStartup(e);

    Window aWindow = new Window();

    aWindow.ShowDialog();

    }

    public void InitializeComponent()

    {

    AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

    DispatcherUnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(App_DispatcherUnhandledException);

    }

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)

    {

    }

    void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)

    {

    e.Handled = true;

    System.Console.WriteLine("DispatcherUnhandledException captured!");

    }

    }

    }

     

     

     

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Windows;

    using System.Windows.Controls;

    using System.Windows.Data;

    using System.Windows.Documents;

    using System.Windows.Input;

    using System.Windows.Media;

    using System.Windows.Media.Imaging;

    using System.Windows.Shapes;

    using System.Threading;

    using System.Windows.Threading;

     

    namespace DispatcherUnhandledExceptionApplication

    {

    /// <summary>

    /// Interaction logic for Window1.xaml

    /// </summary>

    public partial class Window : System.Windows.Window

    {

    public Window()

    {

    InitializeComponent();

    }

    void OnUIThreadButtonClicked(object sender, EventArgs e)

    {

    RaiseArgumentNullException();

    }

    void OnThreadPoolButtonClicked(object sender, EventArgs e)

    {

    ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state)

    {

    try

    {

    Dispatcher.CurrentDispatcher.UnhandledException += new DispatcherUnhandledExceptionEventHandler(CurrentDispatcher_UnhandledException);

    int aDomainID = AppDomain.CurrentDomain.Id;

    Thread.CurrentThread.Name = "MyThreadPoolThread";

    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal, new MyDlg(RaiseArgumentNullException));

    }

    catch (Exception ex)

    {

    throw ex;

    }

    finally

    {

    Dispatcher.CurrentDispatcher.UnhandledException -= new DispatcherUnhandledExceptionEventHandler(CurrentDispatcher_UnhandledException);

    }

    }));

    }

    void CurrentDispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)

    {

    e.Handled = false;

    }

    delegate void MyDlg();

    void RaiseArgumentNullException()

    {

    throw new ArgumentNullException();

    }

    }

     

     

     

     

     

    <Window x:Class="DispatcherUnhandledExceptionApplication.Window"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="WindowsApplication17" Height="97" Width="300"

    >

    <Grid>

    <Button Height="23" Click="OnThreadPoolButtonClicked" Margin="0,17,115,0" Name="button2" VerticalAlignment="Top" HorizontalAlignment="Right" Width="75">ThreadPool</Button>

    <Button Height="23" Click="OnUIThreadButtonClicked" HorizontalAlignment="Right" Margin="0,17,22,0" Name="button3" VerticalAlignment="Top" Width="75">UI Thread</Button>

    </Grid>

    </Window>

     

    Thanks,

    Jonas

    Monday, January 29, 2007 3:09 PM

Answers

  • Jonas, the statement in the documentation is wrong. Application.Current.DispatcherUnhandledException is just shorthand for Application.Current.Dispatcher.UnhandledException, making access to the event thread-safe.

    If you want to have something like centralized exception handling, with the ability to swallow the exception, you could follow this pattern:

    1. Make the Dispatcher object of the main thread available to your worker thread. (You could either pass it as a parameter to the thread start method or just use Application.Current.Dispatcher.)
    2. Use a try-catch-finally in the worker thread. (In general, the catch block should immediately rethrow critical exceptions: OutOfMemoryException, SecurityException, SEHException, maybe also NullReferenceException.)
    3. The catch block calls mainDispatcher.Invoke(DispatcherPriority.Send, ExceptionCallback, exception).
    4. ExceptionCallback() throws the exception object passed to it. This happens on the main thread, so handlers added to Application.DispatcherUnhandledException will be invoked and can "handle" the exception.
    5. If your worker thread resumes execution, the exception was "handled."
    Wednesday, February 07, 2007 5:54 PM

All replies

  • Jonas, the statement in the documentation is wrong. Application.Current.DispatcherUnhandledException is just shorthand for Application.Current.Dispatcher.UnhandledException, making access to the event thread-safe.

    If you want to have something like centralized exception handling, with the ability to swallow the exception, you could follow this pattern:

    1. Make the Dispatcher object of the main thread available to your worker thread. (You could either pass it as a parameter to the thread start method or just use Application.Current.Dispatcher.)
    2. Use a try-catch-finally in the worker thread. (In general, the catch block should immediately rethrow critical exceptions: OutOfMemoryException, SecurityException, SEHException, maybe also NullReferenceException.)
    3. The catch block calls mainDispatcher.Invoke(DispatcherPriority.Send, ExceptionCallback, exception).
    4. ExceptionCallback() throws the exception object passed to it. This happens on the main thread, so handlers added to Application.DispatcherUnhandledException will be invoked and can "handle" the exception.
    5. If your worker thread resumes execution, the exception was "handled."
    Wednesday, February 07, 2007 5:54 PM
  • FYI - The Application.DispatcherUnhandledException doc is being updated to be more precise. Also, I am trying to put in a couple of related samples:

    1) How to pass an exception from a background UI thread (thread with a Dispatcher) to the main UI thread
    2) How to pass an exception from a background worker thread (thread without a Dispatcher) to the main UI thread

    Thanks for the good question.

    Monday, February 12, 2007 10:45 PM
  • Michael,
     
    I'm in the midst of designing an error handling framework for my company's first WPF applications. If you could provide the samples you mentioned above here or to me by email it would be a great help. I am particularly concerned with how to best handle the two scenarios you mention above.
     
    Also, in the sample WPF app I'm coding in VS 2005, I'm not seeing where to hook up the DispatcherUnhandledExceptionEventHandler I've written. The expamples I've seen place this in the App's Main method, but that method resides in the App.g.cs file and is not to be hand-edited by developers.
     
    Thanks in advance for any help you (or anyone reading this) can provide.
    Will.
    Thursday, February 22, 2007 8:54 PM
  • For anyone stumbling across this thread, I've got a blog post about the implementation of this here:
    http://www.jimandkatrin.com/codeblog/2008/06/wpf-worker-thread-exceptions.html


    negative ghostrider - the pattern is full
    Saturday, October 25, 2008 3:11 AM
  • The URL mentioned in Jim Roger's post of October 25, 2008 no longer works.  The following URL works:

    http://www.jimandkatrin.com/CodeBlog/2008/06/default.aspx

    Tuesday, June 01, 2010 7:34 PM