WPF Datagrid 的“按下删除键”事件是啥?

Posted

技术标签:

【中文标题】WPF Datagrid 的“按下删除键”事件是啥?【英文标题】:What is the "pressed the delete key" event for the WPF Datagrid?WPF Datagrid 的“按下删除键”事件是什么? 【发布时间】:2010-10-15 04:59:30 【问题描述】:

我想让用户突出显示 WPF DataGrid 上的一行并按删除键删除该行。

该功能已经内置在网格的 UI 中,因此对于用户而言,该行消失了 我目前在 SelectionChanged 事件上处理这个问题(代码如下) 我遍历所有“e.RemovedItems”并使用 LINQ 删除它们

问题是:即使您只是选择一行并移开它,选择更改也会被触发并且该行位于 e.RemovedItems 中(这很奇怪,为什么要简单地选择一些东西把它放在 RemovedItems 容器中?)。

所以我正在寻找一个 DeleteKeyPressed 事件,以便我可以简单地处理它。那个事件叫什么?

我正在使用 2009 年 3 月的工具包。

XAML:

<Grid DockPanel.Dock="Bottom">
    <toolkit:DataGrid x:Name="TheDataGrid" 
                      SelectionChanged="TheDataGrid_SelectionChanged"
                      AutoGenerateColumns="True"
                      RowEditEnding="TheDataGrid_RowEditEnding"/>

代码隐藏:

private void TheDataGrid_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)

    if (e.RemovedItems.Count > 0)
    
        Message.Text = "The following were removed: ";
        foreach (object obj in e.RemovedItems)
        
            Customer customer = obj as Customer;
            Message.Text += customer.ContactName + ",";
            _db.Order_Details.DeleteAllOnSubmit(
                customer.Orders.SelectMany(o => o.Order_Details));
            _db.Orders.DeleteAllOnSubmit(customer.Orders);
            _db.Customers.DeleteOnSubmit(customer);
         
    

    try
    
        _db.SubmitChanges();
    
    catch (Exception ex)
    
        Message.Text = ex.Message;
    


回答:

感谢 lnferis,这正是我要找的,这是我为数据网格完成的删除处理事件,请注意 KeyDown 事件由于某种原因不会触发。

XAML:

<toolkit:DataGrid x:Name="TheDataGrid" 
                  KeyDown="TheDataGrid_KeyDown"
                  PreviewKeyDown="TheDataGrid_PreviewKeyDown"
                  AutoGenerateColumns="True"
                  RowEditEnding="TheDataGrid_RowEditEnding"/>

代码隐藏

private void TheDataGrid_PreviewKeyDown(object sender, KeyEventArgs e)

    if (e.Key == Key.Delete)
    
        var grid = (DataGrid)sender;

        if (grid.SelectedItems.Count > 0)
        
            string checkMessage = "The following will be removed: ";

            foreach (var row in grid.SelectedItems)
            
                Customer customer = row as Customer;
                checkMessage += customer.ContactName + ",";
            
            checkMessage = Regex.Replace(checkMessage, ",$", "");

            var result = MessageBox.Show(checkMessage, "Delete", MessageBoxButton.OKCancel);
            if (result == MessageBoxResult.OK)
            
                foreach (var row in grid.SelectedItems)
                
                    Customer customer = row as Customer;
                    _db.Order_Details.DeleteAllOnSubmit(
                        customer.Orders.SelectMany(o => o.Order_Details));
                    _db.Orders.DeleteAllOnSubmit(customer.Orders);
                    _db.Customers.DeleteOnSubmit(customer);
                
                _db.SubmitChanges();
            
            else
            
                foreach (var row in grid.SelectedItems)
                
                    Customer customer = row as Customer;
                    LoadData();
                    _db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, customer); //TODO: this doesn't refresh the datagrid like the other instance in this code
                
            
        
    


private void TheDataGrid_KeyDown(object sender, KeyEventArgs e)

    Console.WriteLine("never gets here for some reason");

【问题讨论】:

KeyDown 永远不应该到达这里,因为它已经是气泡中前一个处理程序中的处理程序(e.Handled = true)。 【参考方案1】:

您要处理 KeyUp 或 KeyDown 事件并检查按下的键是否删除。

private void OnKeyDown(object sender, KeyEventArgs e) 
  if ( Key.Delete == e.Key ) 
    // Delete pressed
  

【讨论】:

当我按下一个键(奇数)时,KeyDown 事件不会触发,但 PreviewKeyDown 可以工作【参考方案2】:

RemovedItems 项目反映了从选择中删除的项目,而不是从网格中删除的项目。

处理PreviewKeyDown 事件,并使用SelectedItems 属性删除那里的选定行:

private void PreviewKeyDownHandler(object sender, KeyEventArgs e) 
    var grid = (DataGrid)sender;
    if ( Key.Delete == e.Key ) 
        foreach (var row in grid.SelectedItems) 
            ... // perform linq stuff to delete here
        
    

【讨论】:

DataGrid 不只是有 RowsDeleted 事件是否有原因?默认情况下,WPF 会在您按下删除键时以图形方式删除该行。因此,它已经在执行此逻辑并遍历已删除的行。为什么他们不能只添加一个事件处理程序,这样我就不必复制此代码并检查键。 这不是很好,如果您正在编辑单元格并使用删除键删除单元格中的某些字符,您最终会删除整行。 @epalm 如果您像 Edward Tanguay 一样在 if (grid.SelectedItems.Count &gt; 0) 中添加 foreach 代码,那么一切都应该正常工作。但感谢您指出! 以下 epalms 问题的解决方案 grid.SelectedItems.Count 在编辑单元格时也会大于 0,从而导致错误删除行。正如@Kiran Chi 在下面指出的,您可以使用以下代码检查当前选择是否是DataGridCell:if(e.Device.Target.GetType().Name == "DataGridCell")。作为替代方案,您也可以检查e.OriginalSource.GetType().Name【参考方案3】:

您要将 DataGrid 绑定到什么? 理想情况下,您应该对要绑定的集合上的 CollectionChanged 事件做出反应。这样,您的逻辑(删除已删除项目)将与您的 UI 分离。

如果原始集合没有必要的事件,您可以构建一个包含对象的 Observable 集合并将其绑定到 ItemsSource。

它可能不适合您的特定设置,但我通常是这样做的。

【讨论】:

我完全同意这种方法。 ObservableCollection 允许您的 ViewModel 处理对底层数据绑定源的任何更改。您不必依赖代码隐藏......通过代码隐藏完成它并没有什么大错......只是使用 ViewModel 更清洁。 当心这个解决方案引入了与焦点相关的问题(即失去焦点),显然默认的“删除”逻辑与底层集合更改的逻辑完全不同。【参考方案4】:

请按照下面的代码。下面的代码我已经成功了。

如果需要更改,请告诉我。

 private void grdEmployee_PreviewKeyDown(object sender, KeyEventArgs e)
    

        if (e.Device.Target.GetType().Name == "DataGridCell")
        
            if (e.Key == Key.Delete)
            
                MessageBoxResult res = MessageBox.Show("Are you sure want to delete?", "Confirmation!", MessageBoxButton.YesNo,MessageBoxImage.Question);
                e.Handled = (res == MessageBoxResult.No);
            
        
    

【讨论】:

这也可以(而且对我来说听起来更合乎逻辑):if (e.OriginalSource.GetType().Name == "DataGridCell")【参考方案5】:

XAML

<DataGrid ItemsSource="Binding" CommandManager.PreviewCanExecute="Grid_PreviewCanExecute" />

后面的代码

private void Grid_PreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)

  DataGrid grid = (DataGrid)sender;
  if (e.Command == DataGrid.DeleteCommand)
  
    if (MessageBox.Show(String.Format("Would you like to delete 0", (grid.SelectedItem as Person).FirstName), "Confirm Delete", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
      e.Handled = true;
  

【讨论】:

【参考方案6】:

聚会有点晚了,但为了让 Inferis 的回答起作用:

Dim isEditing = False
AddHandler dg.BeginningEdit, Sub() isEditing = True
AddHandler dg.RowEditEnding, Sub() isEditing = False
AddHandler dg.PreviewKeyDown, Sub(obj, ev) 
  If e.Key = Key.Delete AndAlso Not isEditing Then ...

这修复了 epalms 注释:“如果您正在编辑单元格并使用删除键删除单元格中的某些字符,您最终会删除整行”

【讨论】:

【参考方案7】:

最干净的解决方案是使用 PreviewCanExecute,就像 flux 回答的那样,这是一个完整的解决方案,可以让任何像我一样忽略他的答案的人更清楚:

private void Grid_PreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)

    if (e.Command == DataGrid.DeleteCommand)
    
        if (MessageBox.Show($"Delete something from something else?", "Confirm removal of something", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
        
            // Do what ever needs to be done when someone deletes the row
        
        else
        
            e.Handled = true;   
            // Handled means.. no worries, I took care of it.. and it will not delete the row
        
    

此后无需连接到 CommandManager.Executed。

【讨论】:

以上是关于WPF Datagrid 的“按下删除键”事件是啥?的主要内容,如果未能解决你的问题,请参考以下文章

WPF Datagrid开头的(空)列是啥,称为[重复]

Datagrid行选择事件,WPF

wpf datagrid 的单击事件是那个?

WPF DataGrid CellEditEnded 事件

WPF 触屏事件后触发鼠标事件的问题及 DataGrid 误触问题

WPF Datagrid 行编辑“ENDED”事件