4

イベントハンドラーで例外をスローすると、例外ハンドラーは呼び出されませんか?

開始するための簡素化された例のサンプル コード:

App.xaml

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml"
             DispatcherUnhandledException="App_DispatcherUnhandledException" >
    <Application.Resources/>
</Application>

App.xaml.cs

using System.Windows;
using System.Windows.Threading;

namespace WpfApplication1
{
    public partial class App : Application
    {
        //This method is called when ButtonA is clicked, but not when ButtonB is
        //clicked (and a (random) file is selected ofcourse).
        void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.Message, "An exception occurred", MessageBoxButton.OK, MessageBoxImage.Error);
            e.Handled = true;
        }
    }
}

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="Button A" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="ButtonA_Click"/>
        <Button Content="Button B" HorizontalAlignment="Left" Margin="90,10,0,0" VerticalAlignment="Top" Width="75" Click="ButtonB_Click"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using Microsoft.Win32;
using System;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void ButtonA_Click(object sender, RoutedEventArgs e)
        {
            throw new Exception("Works!");
        }

        private void ButtonB_Click(object sender, RoutedEventArgs e)
        {
            var ofd = new OpenFileDialog();
            ofd.FileOk += (s, ce) => {
                throw new Exception("Does not work!?!?");
            };
            ofd.ShowDialog();
        }
    }
}

私はすでにこの質問この質問を見ましたが、32ビットまたは64ビット、または「ANY CPU」を強制しても機能しません。また、これらの 4 つの(!) ハンドラーのいずれかを設定すると、イベントで例外がスローされたときにいずれのハンドラーも呼び出されません。また、この記事は役に立ちませんでした。

私はVS2012を実行しています(Win8、x64で)、プロジェクトは.Net Framework 4.5を使用しています)。私は何が欠けていますか?私は夢中になっていますか?

わかりやすくするために、メッセージボックスが表示されることを期待しています( をクリックすると表示されますButtonA)、または実際には、App_DispatcherUnhandledExceptionメソッドがまったく呼び出されます。しかし、 をクリックしてもメソッドは呼び出されません (したがって、メッセージボックスは表示されません) ButtonB。との唯一の違いはButtonAButtonB" A" の例外はイベント ハンドラになく、" B" の例外はイベント ハンドラにあるということです。もちろん、ファイルを選択し、OpenFileDialog[開く] をクリックして選択します。デバッガーが起動し、「動作しません!?!?」という例外がスローされ、実行が続行され、メッセージ ボックスが表示されません。

また:私はWPFにかなり慣れていないため、問題の一部である可能性があります:P

編集 1

参考までに、正確な問題を示す 2 つの zip ファイルを次に示します。

  1. シンプル(10Kb)
  2. 拡張(10Kb)

私のコンピューターでは、上記の両方のプロジェクトで、ButtonA によってメッセージボックスが表示されますが、ButtonB (ファイルを選択した後) は表示されません。これまで。「アンマネージ コードのデバッグ」をオンにするかどうかに関係なく。

編集 2

別のマシンで同じコードを実行したところ、次のことがわかりました。

他のマシンでの例外

Exception crossed a native/managed boundaryタイトルに注意してください。実行を再開 (続行) しようとすると、例外がポップアップし続けます。デバッガーが起動すると、私のマシンは次のように表示されます。

私のマシンでの例外

...そして、実行を再開すると、ある種のブラック ホールで例外が消えます。メイン フォームが再び表示され、何も起こりません。

これは、次の設定に関係している必要があります。

境界を越えた例外設定

ただし、このオプションをオン/オフにしても、VS2012 を再起動して一時ファイル(およびプロジェクトの bin/obj ディレクトリ)を削除したり、デフォルトを復元したりしても役に立ちません。

だから...私は今、例外が管理されているものと管理されていないものとの間の境界を越えることに関係していることを知っています。ここで、イベントで例外をスローできるように、この問題を解決する方法を理解する必要がありますFileOk(最終的に、私のコンポーネントもそこでスローできるようにします)。

4

2 に答える 2

5

わかりましたので、問題を解決しました。

グーグルで検索したり、SO をサーフィンしたりしました。結局、ここここに行き着きました。FileOk イベントが別のディスパッチャーでどのように処理されるかが明確になったので、解決策は簡単です。

private void ButtonB_Click(object sender, RoutedEventArgs e)
{
    var ofd = new OpenFileDialog();
    ofd.FileOk += (s, ce) => {
        this.Dispatcher.BeginInvoke((Action)(() =>
        {
            //We can throw:
            throw new Exception("Yay! This exception is now caught by the UnhandledException handler!");

            //or, alternatively, our component can do work that possibly throws:
            Component.DoFoo();
        }));
    };
    ofd.ShowDialog();
}

これにより、例外が正しいディスパッチャに渡され、そこで処理されるようになります。その後、App_DispatcherUnhandledExceptionメソッドが正しく呼び出され、そこから取得できます。

于 2013-10-03T10:49:29.187 に答える