获取WPF数据网格上下文菜单单击行
本文关键字:菜单 单击 上下文 网格 WPF 数据 数据网 获取 | 更新日期: 2023-09-27 18:15:52
我有一个WPF DataGrid
<DataGrid AutoGenerateColumns="False" Name="dataGrid1" IsReadOnly="True" >
<DataGrid.Columns>
<DataGridTextColumn Header="Site" Binding="{Binding Site}" Width="150" />
<DataGridTextColumn Header="Subject" Binding="{Binding Subject}" Width="310" />
</DataGrid.Columns>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" Click="Context_Delete">
<MenuItem.Icon>
<Image Width="12" Height="12" Source="Images/Delete.png" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
我有点击事件处理程序为:
private void Context_Delete(object sender, System.EventArgs e) { }
如何在单击之前获得上下文菜单所在的行?sender
对象是System.Windows.Controls.MenuItem
,而不是DataGridRow
。我如何获得单击上下文菜单的DataGridRow
。(我在后面的代码文件中设置了DataGrid.ItemSource
)
根据您的示例代码,我假设您将您的DataGrid绑定到一个ObservableCollection对象,您将属性Site和Subject绑定到DataGridColumns。
基本上,您需要做的就是找出绑定到已单击的DataGridRow的项是什么,并将其从ObservableCollection中删除。下面是一些示例代码,让您开始:
private void Context_Delete(object sender, RoutedEventArgs e)
{
//Get the clicked MenuItem
var menuItem = (MenuItem)sender;
//Get the ContextMenu to which the menuItem belongs
var contextMenu = (ContextMenu)menuItem.Parent;
//Find the placementTarget
var item = (DataGrid)contextMenu.PlacementTarget;
//Get the underlying item, that you cast to your object that is bound
//to the DataGrid (and has subject and state as property)
var toDeleteFromBindedList = (YourObject)item.SelectedCells[0].Item;
//Remove the toDeleteFromBindedList object from your ObservableCollection
yourObservableCollection.Remove(toDeleteFromBindedList);
}
通常情况下,您不处理行(如果要处理,请再次考虑原因),而是处理视图模型。当您打开上下文菜单时,您选中了您的项目,因此可以通过DataGrid访问它。设置SelectedItem财产。然而,如果你真的需要DataGridRow——你有你的DataGrid。selecteindex,这里有很多关于如何获取行的答案。
为了用一个例子来扩展morincer的观点,我最后使用了一个更简单的方法…
private void MenuItem_OnClickRemoveSource(object sender, RoutedEventArgs e)
{
if (SourceDataGrid.SelectedItem == null) return; //safety first
_importViewModel.SourceList.Remove((SourceFileInfo)SourceDataGrid.SelectedItem);
}
对于我来说,
_importViewModel.SourceList
是行绑定到的ObservableCollection。因此,根据最佳实践,我简单地从集合中删除所选项目,由绑定处理UI。
dsfgsho的答案对我有效,但是右键单击网格行不会自动选择它。这意味着,如果您的焦点在其他地方,并且您右键单击并选择上下文菜单项,则可能会在项上获得超出范围的异常。SelectedCells[0],或者如果您选中了一行,然后右键单击另一行,您可能会得到意想不到的结果。
我通过在Datagrid上处理"PreviewMouseRightButtonDown"来处理这个问题。这里,我在右键单击一行时显式地选择一行。我忘了我的UIHelpers类是从哪里来的(可能在这个网站的其他地方)——我用它来解决拖拽问题;Drop items),但如果你遇到这个问题,这应该会给你指明正确的方向。这是可接受答案的扩展:
// handle right mouse click to select the correct item for context menu usage
private void myDataGrid_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
//find the clicked row
DataGridRow row = UIHelpers.TryFindFromPoint<DataGridRow>((UIElement) sender, e.GetPosition(myDataGrid));
if (row == null)
{
Debug.WriteLine("Row is null");
return;
}
else
{
Debug.WriteLine("Grid Row Index is " + row.GetIndex().ToString());
(sender as DataGrid).SelectedIndex = row.GetIndex();
}
}
Elemental Pete的UIHelper可能源于:
http://www.hardcodet.net/2009/03/moving-data-grid-rows-using-drag-and-drop本文列出了包含UIHelper.cs的Zip文件。这不是我的代码,所以这里没有复制/粘贴
dsfgsho接受的答案是有意义的,但是当使用CommandBinding作为标准ApplicationCommands而不是显式的Click事件时,它有点不同,因为发送者不是MenuItem而是DataGrid本身。
XAML:<DataGrid.CommandBindings>
<CommandBinding Command="Cut" CanExecute="DataGrid_CanCut" Executed="DataGrid_Cut" />
<CommandBinding Command="Copy" CanExecute="DataGrid_CanCopy" Executed="DataGrid_Copy" />
<CommandBinding Command="Paste" CanExecute="DataGrid_CanPaste" Executed="DataGrid_Paste" />
<CommandBinding Command="New" CanExecute="DataGrid_CanAddNew" Executed="DataGrid_AddNew" />
<CommandBinding Command="Delete" CanExecute="DataGrid_CanDelete" Executed="DataGrid_Delete" />
</DataGrid.CommandBindings>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Command="Cut" />
<MenuItem Command="Copy" />
<MenuItem Command="Paste" />
<MenuItem Command="New" />
<MenuItem Command="Delete" />
<Separator />
<MenuItem Header="Test" Command="{Binding CustomContextCommand}" />
</ContextMenu>
</DataGrid.ContextMenu>
背后的代码:
private void DataGrid_Delete(object sender, ExecutedRoutedEventArgs e)
{
// Test whether cleared, resolved, etc., and confirm deletion
var datagrid = (DataGrid)sender;
var trans = (DataClasses.BankTransaction)datagrid.SelectedCells[0].Item;
// Take action here; e.g., remove it from the underlying collection, remove it
// from the DB, etc.
e.Handled = true;
}
private void DataGrid_CanDelete(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.Handled = true;
}