How to properly bind to a property in ViewModel from data template
Introduction
Often we face a situation where we have defined a DataTemplate and we need to bind to a property, most often to a Command in ViewModel. To achieve this we will define the binding and will set a RelativeSource for that binding which in some cases can ends up in an error like this. BindingExpression path error: … property not found on ‘object’ … BindingExpression:Path=… DataItem=…
In most of the situation, the binding which is shown above works, but in certain situation like this example, this will fail to bind and if you examine the output window in visual studio, you can see a similar error as below.
BindingExpression path error: […] property not found on ‘object’ […] BindingExpression:Path=[…] DataItem=…
Here in this example, the exact error which you will get is:-
System.Windows.Data Error: BindingExpression path error: ‘CommandHandler’ property not found on ‘object’ ‘‘Grid’ (Name=’’)’. BindingExpression:Path=CommandHandler; DataItem=’Grid’ (Name=’’); target element is ‘Button’ (Name=’’); target property is ‘Command’ (type ‘ICommand’)
How did I fix this?
This happens because, when we define a RelativeSource, WPF tries to resolve the property which we are binding, from the object it finds up in the hierarchy whose type is equal to the type which we have defined for AncestorType. Here the relative source is Grid and Grid object does not have a property called CommandHandler, this is exactly what the error says.
Now if we examine, the Grid object has a property called DataContext, which is set or inherited from its parent to as the ViewModel, and the ViewModel has the property which we need. So a simple fix is to say DataContext.CommandHandler which binds to the CommandHandler property in ViewModel. The final binding is as shown below.