获取WPF数据网格上下文菜单点击的行

25

我有一个WPF数据网格

<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。)
6个回答

42

根据你的示例代码,我认为你将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);
}

这个东西让我免受十分烦躁的时刻所苦。它完美运作。 - coffeecoder

7
通常情况下,你不需要处理行(如果需要,请再次考虑原因)-而是使用视图模型。当你打开上下文菜单时,会选择你的项,因此可以通过DataGrid.SelectedItem属性访问它。但是,如果你真的需要DataGridRow-你有你的DataGrid.SelectedIndex,并且在SO上有很多关于如何获取行的答案,例如获取数据网格中的行

谢谢 morincer。我对 WPF 没有太多的了解,需要在有时间的时候去研究一下。 - O.O.

4
为了举例说明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。


2

dsfgsho的答案对我有用,但是右键单击网格行不会自动选择它。这意味着如果你的焦点在别处,你右键单击并选择上下文菜单项,你可能会在item.SelectedCells[0]上得到一个超出范围的异常,或者如果你选择了一行并在不同的行上右键单击,你可能会得到意外的结果。

我通过处理Datagrid上的“PreviewMouseRightButtonDown”来解决这个问题。在这里,当右键单击行时,我显式地选择一行。我忘记了我的UIHelpers类来自哪里(可能是在这个网站的其他地方 - 我正在使用它来解决拖放项目),但如果你遇到这个问题,这应该指引你朝着正确的方向前进。这是已接受答案的扩展:

// 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();
        }
    }

UIHelpers从这里开始 https://dev59.com/72PVa4cB1Zd3GeqP65PH#10493869 - DAVEWASLIN

0

-1

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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接