Search code examples
c#wpfxamlwpfdatagrid

How to delete selected row in DataGrid using delete key with fixed column


Is there a way I can delete a selected row in DataGrid using delete key with fixed column?

I have used code with command.manager event but it didn't delete the row if i use key down event it executes but it didn't delete the row in data grid. Here is the code I have used:

<Window x:Class="datagridcheck.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="1336" Width="937">
    <Grid  Name="grid1" Margin="10,10,135,10">
        <DataGrid x:Name="dgUsers" SelectionMode="Single" SelectionUnit="CellOrRowHeader" CommandManager.PreviewExecuted="DriversDataGrid_PreviewDeleteCommandHandler"  Margin="174,0,346,0" GridLinesVisibility="None" MinColumnWidth="50" FontFamily="Times New Roman" HorizontalGridLinesBrush="#FFF70000" VerticalGridLinesBrush="#FF0017FF" RowBackground="#FFF5F2D4" FontSize="18" TextOptions.TextHintingMode="Animated" TextOptions.TextFormattingMode="Display" RowDetailsVisibilityMode="Visible" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Top" Width="264" Height="483" IsSynchronizedWithCurrentItem="False" SelectedIndex="0" PreviewKeyDown="dgUsers_PreviewKeyDown"   >
                        <DataGrid.Columns>
                    <DataGridTextColumn Header="FoodName" Width="90" Binding="{Binding FoodName}" MinWidth="90" Foreground="#FFFB1005" FontFamily="Times New Roman"/>
                <DataGridTextColumn Header="Quantity" Width="90" Binding="{Binding Birthday}" MinWidth="90" Foreground="Red" FontFamily="Times New Roman" />
                <DataGridTextColumn Binding="{Binding Id}" ClipboardContentBinding="{x:Null}" Header="Price" MinWidth="90" Width="90"/>
                </DataGrid.Columns>
            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Setter Property="Background" Value="LightBlue" />
                    <Style.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Background" Value="Blue"/>
                            <Setter Property="Foreground" Value="White"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>
        <Button Content="Button" HorizontalAlignment="Left" Margin="443,378,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
        <WrapPanel Height="355" Margin="443,0,0,0" VerticalAlignment="Top" Name="wrap1" HorizontalAlignment="Left" Width="331">
            <WrapPanel Height="100" Width="100"/>
        </WrapPanel>
        <Button Content="Button" HorizontalAlignment="Left" Margin="443,428,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
                <GridView>
                    <GridViewColumn Header="FoodName" Binding="{Binding FoodName}"/>
                    <GridViewColumn Header="Birthday" />
                </GridView>
    </Grid>
</Window>


namespace datagridcheck
          {
           public partial class MainWindow : Window
              {
                  public MainWindow()
                  {
                      InitializeComponent();
                  }
                  int i = 0;
                  private void Button_Click(object sender, RoutedEventArgs e)
                  { 
                      Button bt = new Button();
                      bt.Name = "test";
                      bt.Content="eachtime"+ i.ToString();
                      bt.Width = 50;
                      bt.Height = 50;
                      i++;
                      wrap1.Children.Add(bt);
                      bt.Click += new RoutedEventHandler(this.bt_Click); 
                   }
                  void bt_Click(object sender, RoutedEventArgs e)
                {
                      Button buts = sender as Button;
                      dgUsers.Items.Add(new User() { Id = 1, FoodName = Convert.ToString(buts.Content), Birthday = Convert.ToString(buts.Name) });
                  }
                  private void DriversDataGrid_PreviewDeleteCommandHandler(object sender, ExecutedRoutedEventArgs e)
                          {
                              if (e.Command == DataGrid.DeleteCommand)
                              {
                                  if (!(MessageBox.Show("Are you sure you want to delete?", "Please confirm.", MessageBoxButton.YesNo) == MessageBoxResult.Yes))
                                  {
                                    e.Handled = true;
                                  }
                              }
                          }
               }
              public class User
              {
              public int Id { get; set; }
                      public string FoodName { get; set; }
                      public string Birthday { get; set; }
             }
      }

Solution

  • Quickly MVVM = Model(Data) + View(Screens) + ViewModel(Code+logic)

    First XAML :

    <Window x:Class="WpfApplication2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <DataGrid x:Name="gd"  CanUserDeleteRows="False"  ItemsSource="{Binding DataVMs}" SelectedItem="{Binding SelectedItemInVM, Mode=TwoWay}" AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="True">
    
                <DataGrid.InputBindings>
                    <KeyBinding Gesture="Delete" Key="Delete" Command="{Binding DeleteCommand, Mode=OneWay}"  CommandParameter="{Binding Path=SelectedItem, ElementName=gd, Mode=OneWay}"/>
                </DataGrid.InputBindings>
    
                <DataGrid.Columns>
                    <DataGridTextColumn Header="One" Binding="{Binding Un}" />
                    <DataGridTextColumn Header="Two" Binding="{Binding Deux}" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </Window>
    

    In code Behind of MainWindow add this, assuming DataViewModel wrapps your model:

     public MainWindow()
            {
                InitializeComponent();
    
                //Initialize DataContext with some Data
                var dataContext = new DataViewCollectionModel
                {
                    DataVMs = new ObservableCollection<DataViewModel>()
    
                };
                dataContext.DataVMs.Add(new DataViewModel { Un = 1, Deux = 2 });
                dataContext.DataVMs.Add(new DataViewModel { Un = 10, Deux = 20 });
                dataContext.DataVMs.Add(new DataViewModel { Un = 100, Deux = 200 });
    
                //Assign
                DataContext = dataContext;
            }
    

    Now create You ViewModels :

    1) BindableObject handles the notifications, it's the base class of all Viewmodels:

     public class BindableObject : INotifyPropertyChanged
        {
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void NotifyPropertyChanged(String info)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(info));
                }
            }
    
        }
    

    DataViewCollectionModel is what you pass to the DataContext of your View (In this case MainWindow). it must notify changes. that's why it inherits BindableObject. and it has a list of DataViewModel.

    class DataViewCollectionModel : BindableObject
    {
        private ObservableCollection<DataViewModel> dataVMs;
        private DataViewModel selectedItemInVM;
        public ObservableCollection<DataViewModel> DataVMs
        {
            get { return dataVMs; }
            set
            {
                if (dataVMs != value)
                {
                    dataVMs = value;
                    NotifyPropertyChanged("DataVMs");
                }
            }
        }
    
        public DataViewModel SelectedItemInVM
        {
            get { return selectedItemInVM; }
            set
            {
                if (selectedItemInVM != value)
                {
                    selectedItemInVM = value;
                    NotifyPropertyChanged("SelectedItemInVM");
                }
            }
        }
    
        private RelayCommand<DataViewModel> deleteCommand;
        public RelayCommand<DataViewModel> DeleteCommand
        {
            get { return deleteCommand ?? (deleteCommand = new RelayCommand<DataViewModel>(d => Delete(d))); }
        }
    
        private void Delete(DataViewModel d)
        {
            DataVMs.Remove(selectedItemInVM);
        }
    
    }
    

    and finaly, your DataViewModel wich represents each row in the DataGrid.

     public class DataViewModel : BindableObject
        {
    
            public int Un { get; set; }
            public int Deux { get; set; }
    
        }
    

    And as I am very friendly, I give you a helper that handles commands :

       public class RelayCommand<T> : ICommand
        {
    
            readonly Action<T> _execute = null;
            readonly Predicate<T> _canExecute = null;
    
    
            public RelayCommand(Action<T> execute)
                : this(execute, null)
            {
            }
    
            public RelayCommand(Action<T> execute, Predicate<T> canExecute)
            {
                if (execute == null)
                    throw new ArgumentNullException("execute");
    
                _execute = execute;
                _canExecute = canExecute;
            }
    
            public bool CanExecute(object parameter)
            {
                return _canExecute == null ? true : _canExecute((T)parameter);
            }
    
            public event EventHandler CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
    
            public void Execute(object parameter)
            {
                _execute((T)parameter);
            }
    
        }
    

    To test just click Delete key when you select a Row.

    Hope it helps.