具体来说,我正在使用WPF和MVVM。我有一个MainWindow,它是一个WPF窗口,所有动作都会发生。它使用相应的View Model类作为其属性,命令等。
我在Application.xaml.vb StartUp中设置了主UI线程和非UI线程异常处理程序,如下所示:
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
当我尝试通过故意抛出异常来测试它时,它可以正常工作。它实际上在Sub中的View Model中处理Select All按钮单击。
按钮:
<Button Content="Select All" Height="23" Width="110" Command="{Binding SelectAllCommand}" />
我正在抛出成功捕获的异常的命令:
Private Sub SelectAll()
Throw (New Exception("UI Thread exception"))
SetAllApplyFlags(True)
End Sub
同一个MainWindow中的另一个按钮类似地绑定到命令。但是,它使用一个Task在后台执行其工作,并且在那里抛出的异常不会被我的所有处理程序捕获。
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
有几个类似的问题,但我无法从中找出答案。在大多数情况下,AppDomain UnhandledException似乎是答案,但它不适合我的。我必须添加什么才能捕获可能以这种方式在非UI线程中抛出的异常?
当我在Application.xaml.vb中处理它时,我无法获取TaskScheduler.UnobservedTaskException事件来调用我的事件处理程序。但我从其他答案中得到了提示,我会将其标记为答案,因为它最终有所帮助。
但是,它不在应用程序级别,所以如果这是一个更大的应用程序,我必须在我使用任务的每个实例中复制它。这不是我想要的,但现在不愿意花更多的时间。
我最终在任务中放置了一个try-catch 。在catch中,我能够使用Dispatcher.Invoke来显示一个带有异常信息的用户友好对话框。
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
答案 0 :(得分:1)
TaskScheduler.UnobservedTaskException事件是您要从App start订阅的内容。
当出现故障的Task未观察到的异常即将触发异常升级策略时发生,默认情况下,该策略将终止该进程。
此AppDomain范围事件提供了一种机制,可防止异常升级策略(默认情况下终止进程)触发。
注意:事件可能不会立即被触发(可能会延迟几秒钟)。您可以想象在最终到达UnobservedTaskException事件之前,有一些调用堆栈冒泡和正常异常操作的上下文切换操作。
我想指出的一点是,必须使用通用异常处理程序包装整个应用程序以防止应用程序终止。但是,请记住,对于可能引发异常的所有路径实施适当的异常处理也是必须的。
答案 1 :(得分:1)
桑德拉,
我读了 cscmh99 命题, 拿了你的代码,然后尝试运行,它就可以运行了!
我的意思是您可以订阅到TaskScheduler.UnobservedTaskException
。
然后将抓住UnobservedException
但不会捕获观察到的异常
观察到的异常是来自等待.Wait()
或.Result
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
' Here follows an Unobserved Exception
System.Threading.Tasks.Task.Factory.StartNew(
Sub()
Throw (New Exception("Throwing a background thread exception"))
End Sub)
' Here follows an ObservedException
' ObservedException because there is call to .Wait() (or .Result)
' You can't use UnobservedException for that one
Dim t As Task = System.Threading.Tasks.Task.Factory.StartNew(
Sub()
Throw (New Exception("Throwing a background thread exception"))
End Sub)
t.Wait()
End Sub
以下是工作解决方案的代码:http://1drv.ms/1XOvTbK
此致
答案 2 :(得分:0)
桑德拉,
有一种方法可以从后台任务中捕获异常。
我承认我的解决方案不是全球性的,但至少它可以捕获并防止崩溃!
Private Async Sub Button_Click(sender As Object, e As RoutedEventArgs)
Dim t As Task = 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)
Try
Await t
Catch ex1 As Exception
Debug.WriteLine("Exception from inside task " & ex1.Message)
End Try
End Sub
认为它可以帮助,可能是你,可能是其他人。