Обработка необработанных исключений из связанных свойств MVVM - PullRequest
2 голосов
/ 21 апреля 2020

Я пытаюсь обработать все необработанные исключения в моем приложении WPF.

Я создал фиктивный проект и изменил файл App.xaml.cs, чтобы он выглядел следующим образом

public partial class App : Application
{ 
    public App()
    {
        this.Dispatcher.UnhandledException += (sender, args) =>
        {
            Console.WriteLine("Test1");
        };

        AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
        {
            Console.WriteLine("Test2");
        };

        Application.Current.DispatcherUnhandledException += (sender, args) =>
        {
            Console.WriteLine("Test3");
        };

        AppDomain.CurrentDomain.FirstChanceException += (sender, args) =>
        {
            Console.WriteLine("Test4");
        };
    }
}

У меня также есть этот ViewModel и свойство TestProp, которое я связал с TextBox.Text в XAML:

public class TestViewModel
{
    private string testProp;

    public string TestProp
    {
        get => testProp;
        set
        {
            testProp = value;

            // RAISE EXCEPTION IN PROPERTY SETTER
            throw new Exception("Test Exception");
        }
    }
}

Изменение этого свойства в представлении вызовет исключение, однако ни одно из событий в App.xaml.cs не будет инициировано, кроме FirstChanceException.

The проблема с FirstChanceException, это будет вызвано, даже если я обработаю исключение в коде.

Я просто хочу, чтобы все необработанные исключения обрабатывались глобально, чтобы я мог регистрировать ошибку и отображать диалоговое окно ошибки, не имея обернуть каждый метод получения / установки.

Возможно ли это? Спасибо

1 Ответ

2 голосов
/ 21 апреля 2020

Да, это возможно. Вы должны реализовать событие App.DispatcherUnhandledException. Прочтите эту статью, чтобы узнать, как ее реализовать.

========================== ==================

ОБНОВЛЕНИЕ 1: Да, как упоминал @Maciek Świszczowski в комментарии, вы уже реализовали его в своем исходном коде, это было моя ошибка не замечать этого.

Проблема, с которой вы столкнулись, заключается в том, что создание исключений внутри класса, используемого в качестве модели представления, отправляется в систему проверки WPF. Эта функция известна как «Проверка на объекте данных», и исключение не отправляется в событие App.DispatcherUnhandledException, но входит в систему проверки WPF.

Один из способов создания исключений в уведомлениях объекта данных - глобально обрабатывается в исключении App.DispatcherUnhandledException, чтобы сделать их всплывающими в верхней части приложения. В коде это может быть достигнуто путем добавления класса ExceptionValidationRule в привязку к свойству и генерирования исключения внутри присоединенного события Validation.error, что-то вроде этого:

<Window
    x:Class="WpfApp10.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfApp10"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800" Height="450"
    d:DataContext="{d:DesignInstance Type=local:TestViewModel}"
    mc:Ignorable="d">
    <StackPanel>
        <TextBox Validation.Error="Validation_OnError">
            <TextBox.Text>
                <Binding NotifyOnValidationError="True" Path="TestProp" UpdateSourceTrigger="PropertyChanged">
                    <Binding.ValidationRules>
                        <ExceptionValidationRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
    </StackPanel>
</Window>

и в коде:

public partial class MainWindow : Window {
    public MainWindow() {
        InitializeComponent();
        var vm = new TestViewModel();
        this.DataContext = vm;
        //throw new Exception("Test2 Exception");
    }

    private void Validation_OnError(object sender, ValidationErrorEventArgs e) {
        throw e.Error.Exception;
    }
}

Я тестировал код здесь

...