WPF datagrid implement multi select via behavior selectionchanged event in MVVM
<DataGrid ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" CanUserAddRows="False" AutoGenerateColumns="False" SelectionMode="Extended"> <behavior:Interaction.Triggers> <behavior:EventTrigger EventName="SelectionChanged"> <behavior:CallMethodAction MethodName="DataGrid_SelectionChanged" TargetObject="{Binding}"/> </behavior:EventTrigger> </behavior:Interaction.Triggers> public void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { var dg = e.OriginalSource as DataGrid; if(dg!=null) { var items = dg.SelectedItems?.Cast<Book>().ToList(); if(items!=null && items.Any()) { MessageBox.Show($"Selected {items.Count()}!\n"); } } }
//xaml <Window x:Class="WpfApp26.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:behavior="http://schemas.microsoft.com/xaml/behaviors" xmlns:local="clr-namespace:WpfApp26" mc:Ignorable="d" WindowState="Maximized" Title="MainWindow" Height="450" Width="800"> <Window.DataContext> <local:BookVM/> </Window.DataContext> <Window.Resources> <local:SizeConverter x:Key="sizeConverter"/> </Window.Resources> <Grid> <DataGrid ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" CanUserAddRows="False" AutoGenerateColumns="False" SelectionMode="Extended"> <behavior:Interaction.Triggers> <behavior:EventTrigger EventName="SelectionChanged"> <behavior:CallMethodAction MethodName="DataGrid_SelectionChanged" TargetObject="{Binding}"/> </behavior:EventTrigger> </behavior:Interaction.Triggers> <DataGrid.Columns> <DataGridTextColumn Header="Id" Binding="{Binding Id}"/> <DataGridTextColumn Header="ISBN" Binding="{Binding ISBN}"/> <DataGridTemplateColumn Header="Image"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Border Width="{Binding ActualWidth,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}, Converter={StaticResource sizeConverter}}" Height="{Binding ActualHeight,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}, Converter={StaticResource sizeConverter}}"> <Border.Background> <ImageBrush ImageSource="{Binding ImgSource}" Stretch="Uniform" /> </Border.Background> </Border> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </Grid> </Window> //cs using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Security.Policy; using System.Text; using System.Threading.Tasks; 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 System.IO; using System.Data.SqlTypes; using System.Globalization; namespace WpfApp26 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } public class BookVM: INotifyPropertyChanged { private List<string> imgsList { get; set; } private int imgsCount = 0; public BookVM() { InitData(); } private void InitData() { var imgs = Directory.GetFiles(@"../../Images"); if (imgs != null && imgs.Any()) { imgsCount = imgs.Count(); imgsList = new List<string>(imgs); BooksCollection = new ObservableCollection<Book>(); for(int i=0;i<10000;i++) { Book book = new Book() { Id=i+1, ISBN=$"ISBN_{i+1}", Name=$"Name_{i+1}", Topic=$"Topic_{i+1}", ImgUrl = $"{imgs[i%imgsCount]}", ImgSource=GetImgSource(imgs[i%imgsCount]) }; BooksCollection.Add(book); } } } private ImageSource GetImgSource(string url) { BitmapImage bmi = new BitmapImage(); bmi.BeginInit(); bmi.UriSource=new Uri(url, UriKind.RelativeOrAbsolute); bmi.EndInit(); if(bmi.CanFreeze) { bmi.Freeze(); } return bmi; } public void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { var dg = e.OriginalSource as DataGrid; if(dg!=null) { var items = dg.SelectedItems?.Cast<Book>().ToList(); if(items!=null && items.Any()) { MessageBox.Show($"Selected {items.Count()}!\n"); } } } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { var handler = PropertyChanged; if(handler!=null) { handler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } private ObservableCollection<Book> booksCollection; public ObservableCollection<Book> BooksCollection { get { if (booksCollection==null) { booksCollection = new ObservableCollection<Book>(); } return booksCollection; } set { if(booksCollection!=value) { booksCollection = value; OnPropertyChanged(nameof(BooksCollection)); } } } } public class SizeConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { double d = 0; if(double.TryParse(value?.ToString(), out d)) { return d / 2; } return d; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class Book { public int Id { get; set; } public string Name { get; set; } public string Topic { get; set; } public string ImgUrl { get; set; } public string ISBN { get; set; } public ImageSource ImgSource { get; set; } } }