views:

407

answers:

5

I am new to WPF, I am using VS2010 beta2, .NET 4.0.

Throw new Exception("test") in my code simply swallows exception and application does not crash.

This is not what I expect, I want the application to crash if unhandled exception occurs.

Is there a simple way to achieve this?

Also, neither Application.DispatcherUnhandledException nor AppDomain.UnhandledException is executed. It is probably because all code is executed as part of the data binding (I am using MVVM pattern and exception is thrown in ViewModel constructor).

While debugging I can look into Output window and find out what is wrong. But it seems to me odd, that application simply ignores error, leaves UI in incorrect state and does not crash.

Edit:

It seems that maybe only non-critical binding exceptions should occur while databinding. Maybe extracting functionality which is not directly related to binding (for example connecting to database) out of the binding execution can be the solution. However I am not sure how to achieve it in MVVM.

Simplified example:

XAML:

<DataTemplate DataType="{x:Type vm:ItemViewModel}">
    <vw:ItemControl />
</DataTemplate>

<ContentControl 
 Content="{Binding Path=MyItem}"     
 />  

where MyItem creates and returns instance of ItemViewModel. Problem is that constructor of ItemViewModel is executed as part of the data binding and I am not sure if this is good practice (this constructor contains code which can fail - for example if database is not accessible).

A: 

The why's are answered here and here. They also explain ways to debug the exceptions better. No answers on how to turn them into unhandled exceptions though.

edit: You can instruct bindings to signal an error when a binding gets source updated. See here. Then you can use the ErrorTemplate (or use the default) to show the error in your UI.

{Binding Age, ValidatesOnDataErrors=true}
Lars Truijens
Thanks. I have read that. Unfortunatelly I could not find a way to force application to crash. :-(
Martin 'Pozi' Pozor
Are you sure you want to do that? Exceptions in bindings might occur more often and more naturally then you my expect. See the {Binding Name.Length} example from http://stackoverflow.com/questions/2075289/why-does-wpf-swallow-databinding-exceptions/2075385#2075385
Lars Truijens
In that case you might want to change your title and question so that it is more clear you don't care about the why's.
Lars Truijens
I allways follow practice that exceptions should not be ignored / swallowed. I do not say, I want to do it, if it violates WPF best practices. If there is another way to achieve more logical behaviour, I will go for it.The thing was, that my application was working fine while debugged (F5), otherwise (CTRL+F5) empty window was shown. I found out later that exception is thrown in second case only, but it was hard to find out what is going on (I had to put try/catch with MessageBox to find out). I simply want to avoid these kind of situations.I will look at error template suggestion,thans.
Martin 'Pozi' Pozor
The links in my answer explain the why's and show how to debug. No need to put in any try catch to debug. The output window shows the exceptions and with the right settings you can even make the debugger stop.
Lars Truijens
I am not talking about debugging. I am talking about proper unexpected error handling in released (not debugged) application.Ignoring critical errors is not correct in any way.
Martin 'Pozi' Pozor
Good to see you changed your title and question to make this point more clear.
Lars Truijens
(question updated again)
Martin 'Pozi' Pozor
A: 

I'm pretty sure a poorly designed application using .NET 4 could abuse AppDomain.FirstChanceException for this purpose.

The build log gives you everything you need to know for finding problems in your WPF application. Here's what was logged when I threw a NotImplementedException in some code I knew the UI was bound to:

System.Windows.Data Error: 17 : Cannot get 'ExitCommand' value (type 'RelayCommand') from '' (type 'ControlCenter'). BindingExpression:Path=ExitCommand; DataItem='ControlCenter' (Name='controlCenterWindow'); target element is 'MenuItem' (Name=''); target property is 'Command' (type 'ICommand') TargetInvocationException:'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NotImplementedException: The method or operation is not implemented.
   at Tvl.Client.ControlCenter.get_ExitCommand() in C:\dev\Tvl\Client\ControlCenter.xaml.cs:line 25
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
   at MS.Internal.Data.PropertyPathWorker.GetValue(Object item, Int32 level)
   at MS.Internal.Data.PropertyPathWorker.RawValue(Int32 k)'
280Z28
I want to have my application well designed ;-)
Martin 'Pozi' Pozor
@pozi: Put the log to use (see my update). From there you can use breakpoints or configure Visual Studio to break when an exception of a particular type is thrown (Debug > Exceptions...).
280Z28
Martin 'Pozi' Pozor
A: 

I will answer my question myself:

I achieved proper behavior by moving code which can fail (e.g. database access call) from (data bound) property getter to the constructor of View-Model. Additionaly I have used BackgroundWorker for this call, so code is executed asynchronously. I rethrow possible exception in RunWorkerCompleted - BackgroundWorker guarantees that it will be done on UI thread.

public TestViewModel()
{  
    BackgroundWorker bckgWorker = new BackgroundWorker();
    bckgWorker.DoWork += ((s, e) => this.TestExecuteCode());            
    bckgWorker.RunWorkerCompleted += ((s, e) => 
    { 
        if (e.Error != null) 
            throw e.Error; 
    });

    bckgWorker.RunWorkerAsync();
}

private void TestExecuteCode()
{
    this.DataBoundProperty = LoadDataFromDb();
}

I strongly prefer this approach of getting data asynchronously rather than IsAsync=true setting on Binding in XAML. This approach never swallows Exceptions compared to IsAsync approach when exceptions are thrown on render thread and are swallowed by default.

Warning: When running this code as part of unit tests, RunWorkerCompleted event handler will not be marshaled back to caller's thread by default. SynchronizationContext used by BackgroundWorker must be set manually in order to handle exceptions in unit tests correctly.

Martin 'Pozi' Pozor
A: 

You can catch the exceptions raised during binding and rethrow them - see the answer to this question.

Ian Gregory
Thanks. It is more or less what I have done with BackgroundWorker, but this is straight solution to this problem without asynchronous call.
Martin 'Pozi' Pozor
A: 

.Net 4.0\WPF introduces a way of doing this see answer here

Adrian Russell