wpfmvvmcommandbinding

How to Bind Button to DataGrid Delete Command in WPF


I'd like to delete rows from a WPF DataGrid by clicking a button above (not inside) the DataGrid, following the MVVM pattern. Although delete buttons within a row itself work, they are kind of ugly (one has to select the row first) and as there are also add and edit buttons next to the delete button, a delete button would better fit there, I think. The corresponding part in my ViewModel looks like this:

<Button Grid.Row="0" Grid.Column="0" Content="add"/>
<Button Grid.Row="0" Grid.Column="1" Content="edit"/>
<Button Grid.Row="0" Grid.Column="2" Content="delete"/>
<DataGrid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" 
    ItemsSource="{Binding dataTableListItems}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name"/>
        <!--I don't wan't to use these "in-Row" delete buttons-->
        <DataGridTemplateColumn Header="delete">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button Command="Delete" Content="X"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

Any ideas on how Command Binding for the buttons could look like? Or alternatively, I could also be satisfied if the in-row delete buttons would always be enabled and a click on one would delete the corresponding row without needing to select the row first.


Solution

  • Assuming you're using MVVM, just bind to the SelectedItem of the DataGrid and use it whenever the Command is invoked.

    Example ViewModel:

    public class MyViewModel : INotifyPropertyChanged
    {
        private Item _selectedItem;
        public Item SelectedItem 
        {
            get { return _selectedItem; }
            set
            {
                _selectedItem = value;
                RaisePropertyChanged("SelectedItem");
            }
        }
    
        private ObservableCollection<Item> _dataTableListItems;
        public ObservableCollection<Item> DataTableListItems 
        {
            get { return _dataTableListItems; }
            set
            {
                _dataTableListItems = value;
                RaisePropertyChanged("DataTableListItems")
            }  
        }
    
    
        public ICommand DeleteCommand { get; set; }
    
        public MyViewModel()
        {
            DeleteCommand = new RelayCommand(DeleteSelected);
        }
    
        private void DeleteSelected()
        {
            if (null != SelectedItem)
            {
                DataTableListItems.Remove(SelectedItem);
            }
        }
    }
    

    Updated XAML:

    <Button Grid.Row="0" Grid.Column="0" Content="add"/>
    <Button Grid.Row="0" Grid.Column="1" Content="edit"/>
    <Button Grid.Row="0" Grid.Column="2" Content="delete" Command="{Binding DeleteCommand}"/>
    <DataGrid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" 
        ItemsSource="{Binding dataTableListItems}"
        SelectedItem="{Binding SelectedItem}">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name"/>
            <!--I don't wan't to use these "in-Row" delete buttons-->
            <DataGridTemplateColumn Header="delete">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Button Command="Delete" Content="X"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>