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 > 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 的“按下删除键”事件是啥?的主要内容,如果未能解决你的问题,请参考以下文章