2011-12-06 21 views
2

我有以下情況,在ViewModel中引發的異常不會冒泡到App.xaml.c中的Application_UnhandledException。ViewModel中的Silverlight異常未捕獲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中捕獲所有未處理的異常的一般方法的幫助或指針都非常感謝。

問候, 特拉維斯

+0

什麼正在從您的ViewModel拋出異常類型? – Jacob

+0

那麼它可能是瀏覽器在腳本報告中可能會吃掉異常,通常所有的異常都會被捕獲,但是在Application_Unhandled方法中嘗試設置斷點,它會告訴你它是否到達那裏。 –

回答

2

由於運行時允許您使用的例外是爲了進行驗證,運行時的get-價有所值的綁定操作是在一個大的try-catch塊。

查看ILSpy中的System.Windows.Data.BindingExpression.UpdateValue()以獲取詳細信息(在System.Windows中,WPF版本可能更容易理解(UpdateSource))。

我不認爲有可能自定義運行時的行爲來重新拋出自己的異常。你可以從代碼中看到它重新拋出一些關鍵的東西。

OutOfMemoryException, StackOverflowException, AccessViolationException, ThreadAbortException 

由於其他異常不會被重新拋出,所以它們實際上已被處理。

我認爲你的解決方案是捕獲跟蹤,或者在屬性設置器中擁有你自己的異常處理。

+0

感謝指針@foson。在視圖中我簡單地訂閱了BindingValidationError事件。然後我在處理程序中放置了一些通用的異常處理。僅供參考...爲了使這個事件觸發,需要在Binding上設置一些屬性。例如, _binding.ValidatesOnExceptions = true; _binding.NotifyOnValidationError = true; –

+0

您不需要在所有屬性設置器中添加您自己的異常處理或捕獲(和解碼)跟蹤。最近我發現瞭如何自動捕獲所有綁定異常。看到我的答案在下面.. –

0

最近我發現怎樣的方式來捕獲所有屬性setter所有具有約束力的異常(在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); 
    } 
}