2

具体的には、MVVM で WPF を使用しています。これは、すべてのアクションが発生する WPF ウィンドウです。プロパティ、コマンドなどに対応するビュー モデル クラスを使用します。

次のように、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 にあります。

ボタン:

<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 に、同様にコマンドにバインドされた別のボタンがあります。ただし、タスクを使用してバックグラウンドで作業を実行し、そこでスローされた例外はキャッチオール ハンドラーによってキャッチされません。

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 イベントを取得してイベント ハンドラーを呼び出すことができませんでした。しかし、私は他の答えからヒントを得ました。最終的には役に立ったので、答えとしてマークします。

ただし、これはアプリケーション レベルではないため、これがより大きなアプリケーションである場合は、タスクを使用したすべてのインスタンスでこれを複製する必要があります。これは私が探していたものではありませんでしたが、今はこれ以上時間を費やすつもりはありません。

Taskにtry-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
4

3 に答える 3

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

あなたかもしれないし、他の人かもしれません。

于 2015-10-13T19:10:30.980 に答える