WPF ShowDialog глотает исключения во время загрузки окна - PullRequest
12 голосов
/ 26 января 2011

Диалоговое окно WPF отображается с использованием метода ShowDialog в классе Window, например, когда кнопка нажата в главном окне, например так.

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var window = new Window1();
                window.ShowDialog();
            }
            catch (ApplicationException ex)
            {
                MessageBox.Show("I am not shown.");
            }
        }

В окне есть событие Loaded, подписанное в xamlнапример:

<Window x:Class="Stackoverflow.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Loaded="Window_Loaded">
    <Grid />
</Window>

В событии Window_Loaded выдается исключение

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        throw new ApplicationException();
    }

Однако исключение не перехватывается перехватом вокруг вызова ShowDialog, и вызов не возвращается.Исключение проглатывается, и окно по-прежнему отображается.

Почему это происходит и как мне поступить с обработкой исключения в событии Window_Loaded окна WPF?Нужно ли перехватывать его в обработчике событий и утилизировать окно вручную?

В WinForms вам необходимо вызвать Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)

, чтобы исключения возникали при вызовах ShowDialog.Есть ли аналогичный переключатель, который нужно установить на WPF?

Ответы [ 5 ]

7 голосов
/ 18 февраля 2011

Я видел эту проблему только на машинах x64 с кодом, скомпилированным с Any Cpu. Изменение вашей программы для компиляции под x84 может исправить это, но у меня были проблемы там в зависимости от наших сборок.
Мое единственное предложение по коду - это следующее, и даже тогда не гарантировано, что он будет поднят. Перехватите исключение и перебросьте его в фоновом режиме.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    try
    {
        /// your code here...
        throw new ApplicationException();
        /// your code here...
    }
    catch (Exception ex)
    {
        if (IntPtr.Size == 8)   // 64bit machines are unable to properly throw the errors during a Page_Loaded event.
        {
            BackgroundWorker loaderExceptionWorker = new BackgroundWorker();
            loaderExceptionWorker.DoWork += ((exceptionWorkerSender, runWorkerCompletedEventArgs) => { runWorkerCompletedEventArgs.Result = runWorkerCompletedEventArgs.Argument; });
            loaderExceptionWorker.RunWorkerCompleted += ((exceptionWorkerSender, runWorkerCompletedEventArgs) => { throw (Exception)runWorkerCompletedEventArgs.Result; });
            loaderExceptionWorker.RunWorkerAsync(ex);
        }
        else
            throw;
    }
}
2 голосов
/ 11 августа 2015

Здесь объясняется «Почему»: http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/

Короче говоря, исключение нельзя распространять в 64-разрядных операционных системах, поскольку существует переход между режимом пользователя и режима ядра.

Тест IntPtr.Size в ответе @midspace не подходит, потому что IntPtr.Size будет равен 4 в процессе x86, работающем в операционной системе x64 (вместо .NET 4 и более необходимо использовать Environment.Is64BitOperatingSystem).

Решение сейчас: используйте другое событие, например ContentRendered, которое вызывается после Loaded или поместите свой код в конструктор окна.

Никогда не используйте Loaded (или OnLoadв Winforms), потому что если там есть исключение, вы не знаете, что может произойти.

Посмотрите также на этот ответ: https://stackoverflow.com/a/4934010/200443

1 голос
/ 28 января 2011

Я также реконструировал ваш ответ в Visual Studio 2010 в пустом проекте WPF 3.5.

Проект работал так, как ожидалось, то есть Window_Loaded вызвал исключение, и он был пойман событием нажатия кнопки.

Так что я не уверен, почему у вас не работает, может быть, попробуйте опубликовать свой App.xml.cs и любой другой код, который вы не показали здесь?

Тем временем я подумал, чтоЯ хотел бы отметить несколько вещей:

WPF действительно обрабатывает «необработанные» исключения немного иначе, чем WinForms.Попробуйте посмотреть на это для начала:

http://msdn2.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx

Похоже, что в WPF нет точного эквивалента для метода SetUnhandledExceptionMode (см. http://social.msdn.microsoft.com/forums/en-US/wpf/thread/955c75f8-9cd9-4158-bed9-544bd7946413). Попробуйте ихСоветы по регистрации обработчика и посмотрите, поможет ли это вам?

Я бы порекомендовал пройтись по вашему коду - установить точку останова в Window_Loaded и посмотреть, что произойдет - обратить особое внимание на стек вызовов.

Удачи!

1 голос
/ 16 февраля 2011

Исследуя это немного подробнее, я обнаружил эту странную запись в блоге, описывающую подобную проблему.

http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/

Как оказалось, это может быть проблема архитектуры 64-битного процессора.Кто бы мог догадаться ?!Это может объяснить, почему некоторые люди не могут воспроизвести проблему на моем простом примере.Я попытался скомпилировать мой пример в «Любой процессор», x64 и x86, но безрезультатно.На x64 все это полностью рухнуло с помощью диалогового окна сбоя Windows.

Так что я думаю, что это ответ без проверки его на 32-битной машине.

0 голосов
/ 27 января 2011

У меня была похожая проблема, и попытка понять, куда она идет, расстраивает.Есть несколько вещей, которые могут вызывать проблемы.

  • Вы вызываете что-нибудь перед вызовом метода InitializeComponent ();?Ранее у меня был метод, вызывающий элементы xaml, которые еще не были инициализированы.
  • Вы пытались нажать F10, чтобы запустить приложение, с помощью Step Over вы увидите точный запуск процесса?
  • Вы проверили свое имя?XAML может проглотить ошибки, такие как неправильное написание методов, а затем возникает исключение во время выполнения, особенно это касается поставщиков DataSet.Вы будете удивлены, что можете избежать неприятностей.
  • Поймать исключение для открытия формы довольно важно, я бы лучше посмотрел на любые иждивенцы (привязки данных или XAML) и сначала разбирался с ними.1010 *

Надеюсь, эти очки помогут .......

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...