问题
I have the following situation where an Exception thrown in a ViewModel does not bubble up to the Application_UnhandledException in App.xaml.cs.
I have an ObservableCollection in the ViewModel bound to the ItemSourceProperty in a ComboBox. The SelectedItemProperty of the ComboBox is bound to a property in the ViewModel.
When the users selects an entry in the ComboBox the property is correctly called in the ViewModel. A bit of logic is performed and another property (call it property2) is set in the ViewModel. However, there is an unhandled exception in property2. The exception just "disappears" - it does not get raised on the UI thread.
Any suggestions for how to generally fix this issue or an approach to catch exceptions on any thread?
Note that we have a custom built MVVM framework. At first, I thought it was an issue with our framework. After many hours debugging, I decided to download Prism4 (http://www.microsoft.com/download/en/confirmation.aspx?id=4922) and see if a similar scenario could be reproduced in the StockTrader reference application.
I can reproduce the exact same scenario! I would be happy to provide details on how to set up the exception in Prism4.
Any help or pointers on a general approach to catch ALL unhandled exceptions in Silverlight is greatly appreciated.
Regards, Travis
回答1:
Since the runtime allows you to use exceptions for validation purposes, the runtime's get-value-for-binding operation is in one big try-catch block.
Take a look at System.Windows.Data.BindingExpression.UpdateValue() in ILSpy for details (in System.Windows. WPF version may be easier to understand (UpdateSource)).
I don't think its possible to customize the behavior of the runtime to rethrow your own exceptions. You can see from the code that it does rethrow some critical ones.
OutOfMemoryException, StackOverflowException, AccessViolationException, ThreadAbortException
Since other exceptions are not rethrown, they are, in fact, handled.
I think your solution is to either capture the trace, or have your own exception handling in property setters.
回答2:
Recently I found the way how to catch all binding exceptions in all property setters (works in 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);
}
}
Then just invoke EnableBindingExceptions method for every your view:
public partial class MyView : UserControl
{
public MyView()
{
InitializeComponent();
Helper.EnableBindingExceptions(this);
}
}
来源:https://stackoverflow.com/questions/8394718/silverlight-exception-in-viewmodel-not-caught-in-application-unhandledexception