Wednesday 16 April 2014


Share/Bookmark

Issue:

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=…

<Window.Resources>
        <DataTemplate x:Key="TestTemplate">
            <DockPanel>
                <Label Content="{Binding}" />
                <Button Command="{Binding CommandHandler, RelativeSource={RelativeSource AncestorType=Grid}}" />
            </DockPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ItemsControl ItemTemplate="{StaticResource TestTemplate}" ItemsSource="{Binding Values}" />
    </Grid>


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.

   <Window.Resources>
        <DataTemplate x:Key="TestTemplate">
            <DockPanel>
                <Label Content="{Binding}"/>
                <Button Command="{Binding DataContext.CommandHandler,RelativeSource={RelativeSource AncestorType=Grid}}" />
            </DockPanel>           
        </DataTemplate>
    </Window.Resources>

    <Grid>
        <ItemsControl ItemsSource="{Binding Values}" ItemTemplate="{StaticResource TestTemplate}" />
    </Grid>
Categories: ,

0 comments:

Post a Comment

Dear reader, Your comment is always appreciated. I will reply to your queries as soon as possible.

1. Make sure to click on the Subscribe By Email link to be notified of follow up comments and replies. Or you can use Subscribe to: Post Comments (Atom) link.
2. Only English comments shall be approved.
3. Please make your comments self-explanatory. Comment in such a way that it explains the comment so that a counter question can be avoided and can be replied with proper answer on the first go.