The MVVM Light Toolkit is one of the most popular MVVM framework that Silverlight developers are using. While it’s very handy for data binding and manipulation, you have to beware that there’s a little difference to handle unhandled exceptions.
Usually you would expect all unhandled exceptions would end up in the automatically generated Application_UnhandledException
event handler in yoru App.xaml.cs file. A lot of developers would create their custom exception class and catch all exceptions in this event handler as a centralized place to process the exceptions and perform appropriate actions accordingly. But, when you try to raise an exception in, say, a property in one of your MVVM Light view model, this may not always be the case.
For example, in my main view model, I have a simple property:
private int _price; public int Price { get { return _price; } set { if (value < 0) throw new MyException("Price cannot be less than 0."); _price = value; RaisePropertyChanged("Price"); } }
Then in the Application_UnhandledException
event handler, I wanted to show the exception message to the users:
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) { if (e.ExceptionObject is MyException) { // Show all MyException's message to the user. e.Handled = true; MessageBox.Show(e.ExceptionObject.Message); } else { // Handle other exceptions here. } }
This looks good enough except one problem, the exception will never end up in the Application_UnhandledException
event handler. This is because in the MVVM Light view model locator (by default the ViewModelLocator.cs
file), uses a static reference of your main model to bind data to your UI components. static reference is probably running in a different system thread then your instantiated UI components. So when you raise your exception in your view model, the exception won’t reach any event handlers that are in a different thread.
The solution to this problem is rather simple: you raise the exception in the same UI thread.
private int _price; public int Price { get { return _price; } set { if (value < 0) { // Throw the exception in the UI thread. App.Current.RootVisual.Dispatcher.BeginInvoke(() => { throw new MyException("Price cannot be less than 0."); }); // Prevent the property from being set to the incorrect value. return; } _price = value; RaisePropertyChanged("Price"); } }
The modified property uses the Dispatcher
object of the current application’s RootVisual
, which is usually your Main Page. The BegainInvoke
function will throw the exception in the same thread of the RootVisual
, which would be the same thread as your application. Thus making the exception catchable in the application’s Application_UnhandledException
event handler.
Note that BeginInvoke
executes the action in another thread. This is an asynchronous operation that does not interrupt your current execution. So you usually need to put in the extra “return;
” statement to manually interrupt the execution if you need to. This is not necessary in a normal case since raising an unhandled exception only interrupts the execution process in it’s own thread.
Note: Catching exceptions in
Application_UnhandledException
may raise performance concern. If you are a Windows Phone 7 developer, you should test your exception catching performance on a real device. In most cases, this will cause perceivable slowness and is usually not a recommended approach.
And above all, follow your mother’s advice and “don’t put anything smaller than your
elbow into your ear”. In the event the noise in your ears is caused by this the best method of relief you have is to address your mental or emotional issues. Ringing in the ears or tinnitus can be prevented by changing a few things about the way you live.
Hi there! Do you use Twitter? I’d like to follow you if that would be okay. I’m undoubtedly enjoying your blog
and look forward to new updates.
When someone writes an article he/she retains the
thought of a user in his/her mind that how a user can understand it.
Thus that’s why this article is outstdanding.
Thanks!