WPF Datagrid mvvm contextmenu menuitem command commandparameter binding to selecteditems
<MenuItem Header="Remove Book" Command="{Binding RemoveBookCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}},Path=PlacementTarget.SelectedItems}"/>
//all //xaml <Window x:Class="WpfApp34.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" WindowState="Maximized" xmlns:local="clr-namespace:WpfApp34" mc:Ignorable="d" Title="{Binding BooksCollectionCount,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="450" Width="800"> <Grid> <DataGrid ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" SelectionMode="Extended" AutoGenerateColumns="False" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.CacheLength="1" VirtualizingPanel.CacheLengthUnit="Item"> <DataGrid.RowStyle> <Style TargetType="{x:Type DataGridRow}"> <Setter Property="Height" Value="500"/> <Setter Property="FontSize" Value="30"/> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Height" Value="1000"/> <Setter Property="FontSize" Value="50"/> </Trigger> </Style.Triggers> </Style> </DataGrid.RowStyle> <DataGrid.Columns> <DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Border> <Border.Background> <ImageBrush ImageSource="{Binding DataContext.ImgSource, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridRow}}}" Stretch="Uniform"/> </Border.Background> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Text="{Binding Id}" Grid.Row="0" Grid.Column="0"/> <TextBlock Text="{Binding Name}" Grid.Row="0" Grid.Column="1"/> <TextBlock Text="{Binding Title}" Grid.Row="0" Grid.Column="2"/> <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding ISBN}"/> </Grid> </Border> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> <DataGrid.ContextMenu> <ContextMenu> <MenuItem Header="Add Book" Command="{Binding AddBookCommand}"/> <MenuItem Header="Remove Book" Command="{Binding RemoveBookCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}},Path=PlacementTarget.SelectedItems}"/> <MenuItem Header="Edit Book" Command="{Binding EditBookCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}},Path=PlacementTarget.SelectedItems}"/> </ContextMenu> </DataGrid.ContextMenu> </DataGrid> </Grid> </Window> //cs using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Runtime.CompilerServices; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WpfApp34 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); var vm = new MainVM(); this.DataContext = vm; } } public class MainVM : NotifyBase { //EditWindow editWin { get; set; } public MainVM() { InitBooks(); InitCommands(); } private void InitCommands() { AddBookCommand = new DelCommand(AddBookCommandExecuted); RemoveBookCommand = new DelCommand(RemoveBookCommandExecuted); EditBookCommand = new DelCommand(EditBookCommandExecuted); ConfirmCommand = new DelCommand(ConfirmCommandExecuted); CancelCommand = new DelCommand(CancelCommandExecuted); TextChangedCommand = new DelCommand(TextChangedCommandExecuted); } private void TextChangedCommandExecuted(object? obj) { } private void AddBookCommandExecuted(object? obj) { } private void RemoveBookCommandExecuted(object? obj) { var items = (obj as System.Collections.IList).Cast<Book>()?.ToList(); if (items == null && !items.Any()) { return; } var msgBox = MessageBox.Show("Delete Selected Items?", "Delete", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes); if (msgBox == MessageBoxResult.Yes) { foreach (var item in items) { BooksCollection.Remove(item); } } } private void EditBookCommandExecuted(object? obj) { //var items = (obj as System.Collections.IList).Cast<Book>()?.ToList(); //if (items == null && !items.Any()) //{ // return; //} //editWin = new EditWindow(); //editWin.DataContext = this; //SelectedBooks = new ObservableCollection<Book>(items); //if (editWin.ShowDialog() == true) //{ //} } private void ConfirmCommandExecuted(object? obj) { //editWin.DialogResult = true; } private void CancelCommandExecuted(object? obj) { //editWin.DialogResult = false; } public DelCommand AddBookCommand { get; set; } public DelCommand RemoveBookCommand { get; set; } public DelCommand EditBookCommand { get; set; } public DelCommand ConfirmCommand { get; set; } public DelCommand CancelCommand { get; set; } public DelCommand TextChangedCommand { get; set; } int index = 0; private void InitBooks() { var dir = @"../../../Images"; if (Directory.Exists(dir)) { var imgs = Directory.GetFiles(dir); int imgsCount = imgs.Count(); BooksCollection = new ObservableCollection<Book>(); SelectedBooks = new ObservableCollection<Book>(); BooksCollection.CollectionChanged += BooksCollection_CollectionChanged; for (int i = 0; i < 10000; i++) { var bk = new Book() { Id = ++index, Name = $"Name_{index}", Title = $"Title_ {index}", ISBN = $"ISBN-{Guid.NewGuid().ToString("N")}", ImgSource = new BitmapImage(new Uri(imgs[i % imgsCount], UriKind.RelativeOrAbsolute)) }; BooksCollection.Add(bk); } } } private void BooksCollection_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { BooksCollectionCount = BooksCollection.Count; } private int booksCollectionCount; public int BooksCollectionCount { get { return booksCollectionCount; } set { if (value != booksCollectionCount) { booksCollectionCount = value; OnPropertyChanged(); } } } private ObservableCollection<Book> booksCollection; public ObservableCollection<Book> BooksCollection { get { return booksCollection; } set { if (value != booksCollection) { booksCollection = value; OnPropertyChanged(); BooksCollectionCount = BooksCollection.Count; } } } private ObservableCollection<Book> selectdBooks; public ObservableCollection<Book> SelectedBooks { get { return selectdBooks; } set { if (value != selectdBooks) { selectdBooks = value; OnPropertyChanged(); } } } } public class Book: NotifyBase { public int Id { get; set; } private string name; public string Name { get { return name; } set { if (value!=name) { name = value; OnPropertyChanged(nameof(Name)); } } } private string title; public string Title { get { return title; } set { if(value != title) { title = value; OnPropertyChanged(); } } } private string iSBN; public string ISBN { get { return iSBN; } set { if (value != iSBN) { iSBN = value; OnPropertyChanged(); } } } public ImageSource ImgSource { get; set; } } public class DelCommand : ICommand { private Action<object?> execute; private Predicate<object?> canExecute; private DelCommand textChangedCommand; public DelCommand(DelCommand textChangedCommand) { this.textChangedCommand = textChangedCommand; } public DelCommand(Action<object?> executeValue, Predicate<object?> canExecuteValue = null) { execute = executeValue; canExecute = canExecuteValue; } public event EventHandler? CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object? parameter) { return canExecute == null ? true : canExecute(parameter); } public void Execute(object? parameter) { execute(parameter); } } public class NotifyBase: INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }