Catch-all Exception Handler for non-UI Threads in WPF <p>Specifically, I'm using WPF with MVVM. I have a MainWindow, which is a WPF Window where all of the action happens. It uses a corresponding View Model class for its properties, commands, etc.</p> <p>I have set up main UI thread and non-UI thread exception handlers in Application.xaml.vb StartUp like this:</p> <pre class="lang-VB.Net prettyprint-override"><code>Private Sub Application_DispatcherUnhandledException(sender As Object, e As Windows.Threading.DispatcherUnhandledExceptionEventArgs) Handles Me.DispatcherUnhandledException ' catches main UI thread exceptions only ShowDebugOutput(e.Exception) e.Handled = True End Sub Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup ' catches background exceptions Dim currentDomain As AppDomain = AppDomain.CurrentDomain AddHandler currentDomain.UnhandledException, AddressOf UnhandledExceptionHandler AddHandler System.Threading.Tasks.TaskScheduler.UnobservedTaskException, AddressOf BackgroundTaskExceptionHandler End Sub Sub UnhandledExceptionHandler(sender As Object, args As UnhandledExceptionEventArgs) Dim ex As Exception = DirectCast(args.ExceptionObject, Exception) ShowDebugOutput(ex) End Sub Sub BackgroundTaskExceptionHandler(sender As Object, args As System.Threading.Tasks.UnobservedTaskExceptionEventArgs) Dim ex As Exception = DirectCast(args.Exception, Exception) ShowDebugOutput(ex) End Sub </code></pre> <h2>This part works</h2> <p>When I try to test this out, by deliberately throwing an exception, it works. It is actually in the View Model in the Sub that handles the Select All button click.</p> <p>The button:</p> <pre><code>&lt;Button Content="Select All" Height="23" Width="110" Command="{Binding SelectAllCommand}" /&gt; </code></pre> <p>The Command where I'm throwing the exception that is successfully caught:</p> <pre class="lang-VB.Net prettyprint-override"><code>Private Sub SelectAll() Throw (New Exception("UI Thread exception")) SetAllApplyFlags(True) End Sub </code></pre> <h2>This part doesn't work</h2> <p>There's another button in the same MainWindow similarly bound to a command. However, it uses a Task to perform its work in the background, and an exception thrown in there does NOT get caught by my catch-all handlers.</p> <pre class="lang-VB.Net prettyprint-override"><code>Private Sub GeneratePreview() ' run in background System.Threading.Tasks.Task.Factory.StartNew( Sub() ' ... stuff snipped out, issue is the same with or without the rest of the code here ... Throw (New Exception("Throwing a background thread exception")) End Sub) End Sub </code></pre> <p>There are several similar questions, but I haven't been able to actually figure out my answer from them. The AppDomain UnhandledException seems to be the answer in most cases, but it isn't for mine. What exactly do I have to add to be able to catch an exception that might be thrown in a non-UI thread this way?</p> <h2>What I ended up doing</h2> <p>I could not get the TaskScheduler.UnobservedTaskException event to call my event handler when I was handling it in Application.xaml.vb. But I took hints from the other answer, and I'll mark it as the answer because it ultimately helped.</p> <p>However, it is not at the application level, so if this was a larger application, I'd have to duplicate this in every instance where I used a Task. This wasn't really what I was looking for, but not willing to spend more time on it now.</p> <p>I ended up putting a try-catch <em>inside</em> the Task. In the catch, I was able to use Dispatcher.Invoke to still display a user-friendly dialog with the exception info.</p> <pre class="lang-VB.Net prettyprint-override"><code>Private Sub GeneratePreview() ' run in background System.Threading.Tasks.Task.Factory.StartNew( Sub() Try ' ... stuff snipped out, issue is the same with or without the rest of the code here ... Throw (New Exception("Throwing a background thread exception")) Catch ex As Exception Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, DirectCast( Sub() HRNetToADImport.Application.ShowDebugOutput(ex) End Sub, Action)) End Try End Sub) End Sub </code></pre>