【问题标题】:Silverlight exception in ViewModel not caught in Application_UnhandledExceptionViewModel 中的 Silverlight 异常未在 Application_UnhandledException 中捕获
【发布时间】:2011-12-06 02:40:35
【问题描述】:

我有以下情况,其中 ViewModel 中引发的异常不会冒泡到 App.xaml.cs 中的 Application_UnhandledException。

我在 ViewModel 中有一个 ObservableCollection,绑定到 ComboBox 中的 ItemSourceProperty。 ComboBox 的 SelectedItemProperty 绑定到 ViewModel 中的一个属性。

当用户在 ComboBox 中选择一个条目时,该属性在 ViewModel 中被正确调用。执行一些逻辑并在 ViewModel 中设置另一个属性(称为 property2)。但是,property2 中有一个未处理的异常。异常只是“消失” - 它不会在 UI 线程上引发。

对于如何普遍解决此问题或在任何线程上捕获异常的方法有什么建议吗?

请注意,我们有一个自定义构建的 MVVM 框架。起初,我认为这是我们框架的问题。经过几个小时的调试,我决定下载 Prism4 (http://www.microsoft.com/download/en/confirmation.aspx?id=4922),看看是否可以在 StockTrader 参考应用程序中重现类似的场景。

我可以重现完全相同的场景!我很乐意提供有关如何在 Prism4 中设置异常的详细信息。

非常感谢有关在 Silverlight 中捕获所有未处理异常的一般方法的任何帮助或指示。

问候, 特拉维斯

【问题讨论】:

  • 你的 ViewModel 抛出了什么类型的异常?
  • 好吧,可能是浏览器在脚本报告中吃到了异常,通常所有异常都会被捕获,但是尝试在 Application_Unhandled 方法中设置断点,这会告诉你它是否到达那里。

标签: silverlight exception mvvm unhandled


【解决方案1】:

由于运行时允许您将异常用于验证目的,因此运行时的 get-value-for-binding 操作位于一个大的 try-catch 块中。

查看 ILSpy 中的 System.Windows.Data.BindingExpression.UpdateValue() 了解详细信息(在 System.Windows 中。WPF 版本可能更容易理解(UpdateSource))。

我认为不可能自定义运行时的行为来重新抛出您自己的异常。你可以从代码中看到它确实重新抛出了一些关键的。

   OutOfMemoryException, StackOverflowException, AccessViolationException, ThreadAbortException

由于其他异常没有被重新抛出,它们实际上是被处理的。

我认为您的解决方案是捕获跟踪,或者在属性设置器中进行自己的异常处理。

【讨论】:

  • 感谢@foson 的指点。在视图中,我只是订阅了 BindingValidationError 事件。然后我在处理程序中放置了一些通用的异常处理。仅供参考...为了触发此事件,需要在绑定上设置一些属性。例如,_binding.ValidatesOnExceptions = true; _binding.NotifyOnValidationError = true;
  • 您不需要在所有属性设置器中添加自己的异常处理或捕获(和解码)跟踪。最近我找到了如何自动捕获所有绑定异常的方法。请参阅下面的答案..
【解决方案2】:

最近我找到了如何在所有属性设置器中捕获所有绑定异常的方法(适用于 Silverlight 5):

public class Helper
{
    public static void EnableBindingExceptions(FrameworkElement element)
    {
        const BindingFlags flags = BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static;
        var fields = element.GetType().GetFields(flags).Where(x => x.FieldType == typeof(DependencyProperty));
        foreach (var field in fields)
        {
            var dp = (DependencyProperty)field.GetValue(null);
            var be = element.GetBindingExpression(dp);
            if (be == null) continue;

            element.SetBinding(dp, new Binding(be.ParentBinding) {ValidatesOnExceptions = true, ValidatesOnNotifyDataErrors = true});
            element.BindingValidationError += OnBindingValidationError;
        }

        var childrenCount = VisualTreeHelper.GetChildrenCount(element);
        for (var i = 0; i < childrenCount; i++)
        {
            var child = VisualTreeHelper.GetChild(element, i) as FrameworkElement;
            if (child == null) continue;

            EnableBindingExceptions(child);
        }
    }

    private static void OnBindingValidationError(object sender, ValidationErrorEventArgs e)
    {
        throw new TargetInvocationException(e.Error.Exception);
    }
}

然后为每个视图调用 EnableBindingExceptions 方法:

public partial class MyView : UserControl
{
    public MyView()
    {
        InitializeComponent(); 
        Helper.EnableBindingExceptions(this);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-16
    • 2017-04-17
    • 2013-06-04
    • 2023-03-26
    相关资源
    最近更新 更多