【问题标题】: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)。

标签: wpf datagrid


【解决方案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。

      【讨论】:

        猜你喜欢
        • 2011-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-04
        • 2011-09-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多