WPF ListBox mvvm contextmenu pass all and multiple items
<MenuItem Header="Export All" Command="{Binding ExportAllCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ContextMenu}},Path=PlacementTarget}" /> <MenuItem Header="Export Selected" Command="{Binding ExportSelectedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ContextMenu}},Path=PlacementTarget.SelectedItems}" />
private void ExportAllCommandExecuted(object? obj)
{
var lbx = obj as ListBox;
if(lbx!=null)
{
var items =((System.Collections.IList)lbx.Items).Cast<Book>()?.ToList();
SaveListTAsJsonFile(items);
}
}
private void ExportSelectedCommandExecuted(object? obj)
{
var selectedItems = ((System.Collections.IList)obj)?.Cast<Book>()?.ToList();
SaveListTAsJsonFile(selectedItems);
}
1. Install-package Microsoft.Xaml.Behaviors.Wpf Install-package Newtonsoft.Json 2. <Window x:Class="WpfApp43.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" xmlns:i="http://schemas.microsoft.com/xaml/behaviors" xmlns:local="clr-namespace:WpfApp43" WindowState="Maximized" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid Background="#000000"> <ListBox x:Name="lbx" Focusable="True" ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectionMode="Extended"> <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged"> <i:CallMethodAction MethodName="ListBox_SelectionChanged" TargetObject="{Binding}"/> </i:EventTrigger> <i:EventTrigger EventName="PreviewMouseWheel"> <i:InvokeCommandAction Command="{Binding MouseWheelCommand}" PassEventArgsToCommand="True"/> </i:EventTrigger> </i:Interaction.Triggers> <!--<ListBox.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel Orientation="Vertical"/> </ItemsPanelTemplate> </ListBox.ItemsPanel>--> <ListBox.ItemTemplate> <DataTemplate> <Grid> <Grid.Background> <ImageBrush ImageSource="{Binding ImgSource}"/> </Grid.Background> <Grid.Resources> <Style TargetType="{x:Type Grid}"> <Setter Property="Height" Value="300"/> </Style> <Style TargetType="{x:Type TextBlock}"> <Setter Property="FontSize" Value="30"/> <Setter Property="Foreground" Value="Black"/> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="FontSize" Value="80"/> <Setter Property="Foreground" Value="Red"/> </Trigger> </Style.Triggers> </Style> </Grid.Resources> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Id}"/> <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Name}"/> <TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding Title}"/> <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Text="{Binding ISBN}"/> </Grid> </DataTemplate> </ListBox.ItemTemplate> <ListBox.ContextMenu> <ContextMenu> <MenuItem Header="Export All" Command="{Binding ExportAllCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ContextMenu}},Path=PlacementTarget}" /> <MenuItem Header="Export Selected" Command="{Binding ExportSelectedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ContextMenu}},Path=PlacementTarget.SelectedItems}" /> </ContextMenu> </ListBox.ContextMenu> </ListBox> </Grid> </Window> //cs using Microsoft.Xaml.Behaviors; using System.Collections; 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; using Newtonsoft.Json; using Microsoft.Win32; using System.Windows.Controls.Primitives; namespace WpfApp43 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); lbx.Items.Clear(); var vm = new MainVM(); this.DataContext = vm; } private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { var lbx = sender as ListBox; if (lbx != null) { var items = lbx.SelectedItems; } } private void lbx_MouseWheel(object sender, MouseWheelEventArgs e) { } private void lbx_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { var bd = e.OriginalSource as Border; if (bd != null) { Console.WriteLine(bd.ActualHeight); } } } public class MainVM : INotifyPropertyChanged { public MainVM() { InitBooksCollection(); //LbxMultiSelectCommand = new DelCommand(LbxMultiSelectCommandExecuted); ExportSelectedCommand = new DelCommand(ExportSelectedCommandExecuted); ExportAllCommand = new DelCommand(ExportAllCommandExecuted); MouseWheelCommand = new DelCommand(MouseWheelCommandExecuted); } private void MouseWheelCommandExecuted(object? obj) { } private void ExportAllCommandExecuted(object? obj) { var lbx = obj as ListBox; if(lbx!=null) { var items =((System.Collections.IList)lbx.Items).Cast<Book>()?.ToList(); SaveListTAsJsonFile(items); } } private void ExportSelectedCommandExecuted(object? obj) { var selectedItems = ((System.Collections.IList)obj)?.Cast<Book>()?.ToList(); SaveListTAsJsonFile(selectedItems); } private void SaveListTAsJsonFile<T>(List<T> dataList) { SaveFileDialog dialog = new SaveFileDialog(); dialog.Filter = "Json Files|*.json|All Files|*.*"; dialog.FileName = $"{DateTime.Now.ToString("yyyyMMddHHmmssffff")}_{Guid.NewGuid().ToString("N")}.json"; if (dialog.ShowDialog() == true) { string jsonStr = JsonConvert.SerializeObject(dataList, Formatting.Indented); File.WriteAllText(dialog.FileName, jsonStr); MessageBox.Show($"Saved {dataList.Count} data in {dialog.FileName}"); } } public void lbx_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { } private void LbxMultiSelectCommandExecuted(object? obj) { } public void lbx_MouseWheel(object sender, MouseWheelEventArgs e) { } public void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { var lbx = sender as ListBox; if (lbx != null) { var items = lbx.SelectedItems; } } private void InitBooksCollection() { BooksCollection = new ObservableCollection<Book>(); var dir = @"../../../Images"; if (Directory.Exists(dir)) { var imgs = Directory.GetFiles(dir); int imgsCount = imgs.Count(); for (int i = 0; i < 1000; i++) { BooksCollection.Add(new Book() { Id = i + 1, Name = $"Name_{i + 1}", Title = $"Title_{i + 1}", ISBN = $"{Guid.NewGuid().ToString("N")}", ImgSource = GetImgSourceVirUrl(imgs[i % imgsCount]), }); } } } private ImageSource GetImgSourceVirUrl(string imgUrl) { BitmapImage bmi = new BitmapImage(); bmi.BeginInit(); bmi.UriSource = new Uri(imgUrl, UriKind.RelativeOrAbsolute); bmi.EndInit(); if (bmi.CanFreeze) { bmi.Freeze(); } return bmi; } public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged([CallerMemberName] string propertyName = "") { var handler = PropertyChanged; if (handler != null) { handler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } private ObservableCollection<Book> booksCollection; public ObservableCollection<Book> BooksCollection { get { return booksCollection ?? (booksCollection = new ObservableCollection<Book>()); } set { if (value != null) { booksCollection = value; OnPropertyChanged(); } } } private ObservableCollection<Book> selectedBooks; public ObservableCollection<Book> SelectedBooks { get { return selectedBooks; } set { if (value != selectedBooks) { selectedBooks = value; OnPropertyChanged(nameof(SelectedBooks)); } } } private bool isSelected; public bool IsSelected { get { return isSelected; } set { if (value != isSelected) { isSelected = value; OnPropertyChanged(); } } } private IList _selectedItems; public IList SelectedItems { get => _selectedItems; set { _selectedItems = value; OnPropertyChanged(); } } public ICommand LbxMultiSelectCommand { get; set; } public ICommand ExportSelectedCommand { get; set; } public ICommand ExportAllCommand { get; set; } public ICommand MouseWheelCommand { get; set; } } public class DelCommand : ICommand { private Action<object?> execcute; private Predicate<object?> canExecute; public DelCommand(Action<object?> execcuteValue, Predicate<object?> canExecuteValue = null) { execcute = execcuteValue; 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) { execcute(parameter); } } public class Book { public int Id { get; set; } public string Name { get; set; } public string Title { get; set; } public string ISBN { get; set; } public ImageSource ImgSource { get; set; } } }