Подтвердить что ты не робот

WPF ShowDialog сглаживает исключения при загрузке окна

Диалоговое окно окна 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?

4b9b3361

Ответ 1

Я только видел эту проблему на машинах 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

Здесь объясняется "Почему": 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 os (вместо этого нужно использовать Environment.Is64BitOperatingSystem вместо .NET 4 и выше).

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

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

Посмотрите также на этот ответ: fooobar.com/questions/2314/...

Ответ 3

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

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

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

В то же время я подумал, что хочу указать несколько вещей:

WPF действительно обрабатывает исключения "uncaught" несколько иначе, чем 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 и посмотреть, что происходит - обратить внимание на стек вызовов.

Удачи!

Ответ 4

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

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

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

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

Ответ 5

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

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

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