【问题标题】:Handling uncaught exceptions from bound MVVM properties处理来自绑定 MVVM 属性的未捕获异常
【发布时间】:2020-04-21 17:09:13
【问题描述】:

我正在尝试处理我的 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 的属性,我已将其绑定到 XAML 中的 TextBox.Text:

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。

FirstChanceException 的问题是,即使我在代码中处理异常,它也会被引发。

我只是希望全局处理所有未处理的异常,这样我就可以记录错误并显示错误对话框,而不必用 try/catch 包装每个 getter/setter。

这可能吗?谢谢

【问题讨论】:

  • 您可以尝试不在构造函数中订阅,而是在 OnStartup() 中订阅吗?
  • @MaciekŚwiszczowski 感谢您的回复。我刚刚尝试过,结果相同 :(。FirstChanceException 是唯一一个命中。
  • 是核心还是框架?有哪些版本?我真的很好奇发生了什么 - 我今天一直在测试 UI 线程上的异常处理(.NET Framework),它很有效。
  • .NET 框架。我从一个简单的新项目中尝试了它,以确保我不会发疯,哈哈。如果我在构造函数中抛出该异常 - 或在其他地方设置该属性,它将触发这些事件。只有当我从视图中设置属性时,它似乎没有触发除“FirstChanceException”之外的任何事件。我的调试器将在 throw 上停止,但它不会冒泡到 App.xaml.cs 中的事件
  • 你能在 Github 上发布你的示例应用吗?

标签: c# wpf mvvm data-binding


【解决方案1】:

是的,这是可能的。您必须实现 App.DispatcherUnhandledException 事件。 查看this 文章,了解如何实现它。

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

更新 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;
    }
}

我测试了代码here

【讨论】:

  • 订阅Application.Current.DispatcherUnhandledException不是也一样吗?
  • @MaciekŚwiszczowski 我相信是的,是的。为了安全起见,我尝试将 DispatcherUnhandledException="App_DispatcherUnhandledException" 添加到 App.xaml 中的 &lt;Application&gt; 标记中(只是为了验证),但它仍然无法正常工作
  • 是的,很抱歉最初的回答。我编辑我的答案。让我知道这是否可以帮助您@AdamPlocher
  • 我测试了实现,但似乎第一次可以工作,但第二次不行?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-30
  • 2017-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-19
相关资源
最近更新 更多