簡體   English   中英

吞下了在事件處理程序中拋出的WPF異常?

[英]WPF exception thrown in eventhandler is swallowed?

當我在事件處理程序中拋出異常時,不會調用異常處理程序?

從以下開始的精簡示例的示例代碼:

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位甚至“任何CPU”都不起作用。 此外,當設置這四個 (!)處理程序中的任何一個時,在事件中拋出異常時,不會調用它們。 這篇文章也沒有幫助。

我正在運行VS2012(在Win8,x64上),該項目正在使用.Net Framework 4.5)。 我錯過了什么? 我瘋了嗎?

為清楚起見:我希望顯示一個消息框(當我單擊ButtonA時它會顯示),或者實際上, App_DispatcherUnhandledException調用的是App_DispatcherUnhandledException方法。 但是當我單擊ButtonB時,不調用該方法( 因此不顯示消息框)。 ButtonAButtonB之間的唯一區別是“ A ”中的異常不在事件處理程序中,而“ B ”中的異常是。 並且,當然,我在OpenFileDialog選擇一個文件,然后單擊“打開”以選擇它。 調試器啟動並指出“ 不工作!?!? ”異常被拋出,然后我繼續執行並且沒有顯示消息框。

另外:我對WPF很新,這可能是問題的一部分 :P

編輯1

作為參考,這里有兩個zipfiles演示確切的問題:

  1. 簡單 (10Kb)
  2. 擴展 (10Kb)

在我的計算機上,對於上述兩個項目,ButtonA會顯示一個消息框,ButtonB(選擇文件后)則不會。 永遠。 甚至無論是否打開“調試非托管代碼”。

編輯2

所以,我在另一台機器上運行相同的代碼並發現了這一點:在另一台機器上,調試器顯示:

其他機器上的例外情況

請注意, Exception crossed a native/managed boundary標題。 當我嘗試恢復執行(繼續)時,異常會不斷彈出。 當調試器啟動時,我的機器顯示:

在我的機器上例外

......然后,當我恢復執行時,異常會在某種黑洞中消失; 主要形式再次顯示,沒有任何反應。

這應該與此設置有關:

邊界交叉異常設置

但是,打開/關閉此選項無效,即使重新啟動VS2012並刪除臨時文件 (以及項目中的bin / obj目錄), 還原默認值等

所以......我現在知道異常,實際上與托管和非托管之間的跨界有關。 現在我只需要弄清楚如何解決這個問題,以便我可以在FileOk事件中拋出異常(這樣,最終,我的組件也可以在那里拋出)。

好的,所以我解決了我的問題。

谷歌搜索,沖浪等等我最終在這里這里結束。 現在我很清楚如何在另一個調度程序上處理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方法,我們可以從那里獲取它。

如果你這樣連線,你會發現它正在被處理
仍然不確定為什么它會逃避App_DispatcherUnhandledException

using System.ComponentModel;
//using Microsoft.Win32;


namespace UncaughtExceptionHandler
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            //AppDomain currentDomain = AppDomain.CurrentDomain;
            //currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
            InitializeComponent();
        }
        private void ButtonA_Click(object sender, RoutedEventArgs e)
        {
            throw new Exception("WTFA!?!?");
        }
        private void ButtonB_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
            ofd.FileOk += MyCanelEventHandler;
            //ofd.FileOk += (s, ce) =>
            //{
            //    //MessageBox.Show("Throwikng Exception WTF2!?!?");
            //    throw new Exception("WTF2!?!?");
            //};
            ofd.ShowDialog();
        }
        static void MyCanelEventHandler(Object sender, CancelEventArgs e)
        {
            MessageBox.Show("MyCanelEventHandler");
            throw new Exception("WTFCEH!?!?");
        }
    }
}

Debug 101獲得一個調用堆棧。
我在10分鍾內得到了一個電話堆棧。

OP做了三個無效的假設,即使經過長時間的討論也無法理解

  1. 吞噬了例外
    它沒有被吞沒它只是越過他未被捕獲的異常處理程序我的代碼證明了但OP沒有遵循
  2. 解決方案沒有無人代碼
    錯誤的OpenFileDialog是非托管代碼
  3. 托管代碼拋出了異常
    又錯了
    異常是從非托管代碼的回調中拋出的

回調中的第一行
Degbug 101獲得一個調用堆棧

UncaughtExceptionHandler.exe!UncaughtExceptionHandler.MainWindow.MyCanelEventHandler(object sender,System.ComponentModel.CancelEventArgs e)第55行C#comdlg32.dll!CFileOpenSave :: _ NotifyFileOkChangeCallback()+ 0x18 bytes comctl32.dll!_DPA_EnumCallback@12()+ 0x20 bytes
comdlg32.dll!CFileOpenSave :: _ NotifyFileOk()+ 0x3d bytes
comdlg32.dll!CFileOpenSave :: _ CleanupDialog()+ 0x46c2字節
comdlg32.dll!CFileOpenSave :: _ HandleOkAndClose()+ 0x3a bytes
comdlg32.dll!CFileOpenSave :: _ OnCommandMessage()+ 0xf432 bytes comdlg32.dll!CFileOpenSave :: s_OpenSaveDlgProc()+ 0x1f42 bytes user32.dll!_InternalCallWinProc@20()+ 0x23 bytes
user32.dll!_UserCallDlgProcCheckWow@32()+ 0xa9個字節
user32.dll!_DefDlgProcWorker@20()+ 0x7f bytes user32.dll!_DefDlgProcW@16()+ 0x22 bytes

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM