Получение контекстного меню сетки данных WPF Нажмите "Строка"

У меня есть DataGrid 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>

У меня есть обработчик события click:

private void Context_Delete(object sender, System.EventArgs e)  { }

Как мне получить строку, на которой находилось контекстное меню до щелчка? Объектом sender является System.Windows.Controls.MenuItem, а не DataGridRow. Как получить DataGridRow, где было нажато контекстное меню. (Я установил DataGrid.ItemSource в код за файлом.)

Ответы

Ответ 1

Итак, основываясь на вашем примере кода, я предполагаю, что вы привязываете свой 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);
}

Ответ 2

Как правило, вы не имеете дело со строками (если хотите - подумайте о причинах) - вместо этого вы работаете с моделью просмотра. Когда вы открываете контекстное меню, вы получаете свой элемент, поэтому его можно получить через свойство DataGrid.SelectedItem. Однако, если вам действительно нужен DataGridRow, у вас есть DataGrid.SelectedIndex, и здесь есть много ответов на SO о том, как получить строку. например Получить строку в datagrid

Ответ 3

Ответ dsfgsho работал у меня, но щелчок правой кнопкой мыши по строке сетки автоматически не выбирает его. Это означает, что если ваш фокус находится где-то в другом месте, и вы щелкните правой кнопкой мыши и выберите пункт контекстного меню, вы можете получить исключение вне диапазона на item.SelectedCells [0], или если у вас есть выбранная строка и щелкните правой кнопкой мыши на другом строка, вы можете получить неожиданные результаты.

Я справился с этим, обработав "PreviewMouseRightButtonDown" в Datagrid. Здесь я явно выбираю строку при щелчке правой кнопкой мыши. Я забыл, откуда пришел мой класс 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();
        }
    }

Ответ 4

Чтобы расширить приведенную выше точку мора на примере, я закончил с более простым подходом...

 private void MenuItem_OnClickRemoveSource(object sender, RoutedEventArgs e)
 {
     if (SourceDataGrid.SelectedItem == null) return;  //safety first

     _importViewModel.SourceList.Remove((SourceFileInfo)SourceDataGrid.SelectedItem);
 }

В моем случае

_importViewModel.SourceList 

- это ObservableCollection, к которому привязаны строки. Поэтому в соответствии с лучшими практиками я просто удаляю выбранный элемент из коллекции, и привязка заботится о пользовательском интерфейсе.