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

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

Setting Up Kafka

Apache Kafka is a high-throughput, low-latency event processing system designed to handle millions of data feeds per second. It has the c...… Continue reading

Libish Varghese Jacob

Libish Varghese JacobI am a lead engineer at a prominent wind turbine manufacturing firm. My interests span a diverse range, and immersing myself in technology is one of them. This platform serves as my primary knowledge base, where I seek information and insights. Moreover, I utilize this platform to share my experiences and experiments, hoping they may benefit those following a similar path. It's important to note that the suggestions I express here are based on my best knowledge at the time of writing and may not necessarily represent the optimal solutions. I wholeheartedly welcome any comments you may have to improve or refine my ideas. Your feedback is greatly appreciated and valued.