3
votes

I have a data grid with few text columns and a Delete button:

<DataGrid ItemsSource="{Binding Customers, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" CanUserAddRows="False" SelectedItem="{Binding SelectedCustomer}"> 
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding FirstName}">
                    <DataGridTextColumn.Header>
                        <Label Content="{DynamicResource FirstName}" />
                    </DataGridTextColumn.Header>
                </DataGridTextColumn>
                <DataGridTextColumn Binding="{Binding LastName}">
                    <DataGridTextColumn.Header>
                        <Label Content="{DynamicResource LastName}" />
                    </DataGridTextColumn.Header>
                </DataGridTextColumn>
                <DataGridTextColumn Binding="{Binding Address}">
                    <DataGridTextColumn.Header>
                        <Label Content="{DynamicResource Address}" />
                    </DataGridTextColumn.Header>
                </DataGridTextColumn>

                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="{DynamicResource Delete}" Command="{Binding DeleteCustomerCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding SelectedCustomer, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
</DataGrid>

Having read this question and answer:

How to use RelativeSource Binding to create DataGrid binding to Model and ViewModel?

I addded the

RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}

part. However, nothing works still. When I debug with Snoop, I can see DataContexts are properly set. The datacontext of the DataGrid is the ViewModel, and it uses the Customers collection property, and the data context of the grid rows are the individual Customer objects, which is expected. I have checked that commands are referred to with their real names and that they're public. Command is initialized in the ViewModel's constructor:

 DeleteCustomerCommand = new RelayCommand<Customer>(DeleteCustomer);

and the Commands are public properties with private setters:

public RelayCommand<Customer> DeleteCustomerCommand { get; private set; }

I only get the following error:

DeleteCustomerCommand' property not found on 'object' ''DataGrid' (Name='')'. BindingExpression:Path=DeleteCustomerCommand; DataItem='DataGrid' (Name=''); target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')

1
Have you checked for any binding errors in the output window when clicking the button?Martin

1 Answers

8
votes

Try add "DataContext" to your command binding:

Command="{Binding DataContext.DeleteCustomerCommand, RelativeSource=...

because there is no DeleteCustomerCommand property on your DataGrid but in the view model connected with the DataGrid.


Additional info

Sometimes it helps me to create a binding for a DataContext with the Visual Studio assistant instead of coding it completely by hand. Just look for the property you want to create a binding for in the property grid of the control.

In this case its the Command property. Left click on the text box for the command property text, then choose "Create data binding..." from the context menu.