WPF MVVM - Bind command of buttons for items in a ListBox to the correct viewmodel

Post date: Jun 16, 2012 11:46:00 AM

When you are binding items inside a DataTemplate in a ListBox the actuall DataContext that you are binding to is not the DataContext of the ListBox.

Instead, the datacontext for those items inside is simply the items in the ListBox.

So, if you try to bind the Command of a button to one of the Commands in your viewmodel then that will not work. If you try then you will get a BindingExpression path error during execution saying that the "CommandName" does not exist.

To actually bind it to the Command in your ViewModel then you need to specify how to find that ViewModel. There are several ways of doing that, you can create a static resource of your ViewModel and then bind the Command of the button to that static resource.

That was not valid in my case since i need a parameter for the constructor of this viewmodel and this viewmodel is created by the MainViewModel. In this case I had to find the DataContext that the ListBox is using when binding the Command. You do this by using the RelativeSource as the example shows below.

FindAncestor will find the ListBox, in the binding I then have to specify that i want to bind to the ListBox's DataContext, and in that DataContext is the command that i actually want to call.

As commandparameter I am sending the item in the list for the row.

Simple!

<ListBox ItemsSource="{Binding Model.ExecutionItems}" SelectedItem="{Binding Model.SelectedExecutionItem, Mode=TwoWay}" Grid.Column="2" ScrollViewer.VerticalScrollBarVisibility="Visible" > <ListBox.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="20" /> <ColumnDefinition Width="200" /> <ColumnDefinition Width="110" /> <ColumnDefinition Width="110" /> <ColumnDefinition Width="40" /> </Grid.ColumnDefinitions> <TextBlock Text="{Binding Order}" Grid.Column="0" /> <TextBlock Text="{Binding Path=TargetTable.TableName}" Grid.Column="1" /> <TextBlock Text="{Binding Path=Description}" Grid.Column="2" /> <TextBlock Text="{Binding Path=RepeatCount}" Grid.Column="3" /> <Button Content="Clone" Command="{Binding Path=DataContext.CloneExecutionItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}" CommandParameter="{Binding .}" Grid.Column="4"></Button> </Grid> </DataTemplate> </ListBox.ItemTemplate> </ListBox>