WPF datagrid mvvm multi select via customize datagrid
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; namespace WpfApp39 { public class MultiSelectDataGrid:DataGrid { public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(IList), typeof(MultiSelectDataGrid), new PropertyMetadata(default(IList))); public new IList SelectedItems { get { return (IList)GetValue(SelectedItemsProperty); } set { throw new Exception("This property is read-only. To bind to it you must use 'Mode=OneWayToSource'."); } } protected override void OnSelectionChanged(SelectionChangedEventArgs e) { base.OnSelectionChanged(e); SetValue(SelectedItemsProperty, base.SelectedItems); } } }
<Window x:Class="WpfApp39.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:local="clr-namespace:WpfApp39" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" mc:Ignorable="d" WindowState="Maximized" Title="MainWindow" Height="450" Width="800"> <Window.Resources> <Style TargetType="DataGridRow"> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="FontSize" Value="30"/> <Setter Property="FontWeight" Value="ExtraBold"/> <Setter Property="Foreground" Value="Red"/> </Trigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <local:MultiSelectDataGrid x:Name="dg" ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectionMode="Extended" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderBrush="Blue" BorderThickness="5" SelectedItems="{Binding SelectedBooks,Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged}" > </local:MultiSelectDataGrid> </Grid> </Window>
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; namespace WpfApp39 { public class MainVM : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propName) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propName)); } } public MainVM() { InitItemsSource(); } private void InitItemsSource() { BooksCollection = new ObservableCollection<Book>(); for(int i=0;i<10000;i++) { BooksCollection.Add(new Book() { Id=i+1, Title=$"Title__{Guid.NewGuid()}", ISBN=$"ISBN__{Guid.NewGuid()}", Name=$"Name_{Guid.NewGuid()}" }); } } private ObservableCollection<Book> booksCollection; public ObservableCollection<Book> BooksCollection { get { return booksCollection; } set { if (value != booksCollection) { booksCollection = value; OnPropertyChanged("BooksCollection"); } } } private ObservableCollection<Book> selectedBooksCollection; public ObservableCollection<Book> SelectedBooksCollection { get { return selectedBooksCollection; } set { if(value != selectedBooksCollection) { selectedBooksCollection = value; OnPropertyChanged("SelectedBooksCollection"); } } } private IList selectedBooks; public IList SelectedBooks { get { return selectedBooks; } set { selectedBooks = value; if(selectedBooks!=null && selectedBooks.Count>0) { MessageBox.Show($"Selected {selectedBooks?.Count} items", "Multi Selected", MessageBoxButton.OK, MessageBoxImage.Information); } } } private DelegateCmd selectedMultiCommand; public DelegateCmd SelectedMultiCommand { get { if (selectedMultiCommand == null) { selectedMultiCommand = new DelegateCmd(SelectedMultiCommandExecuted); } return selectedMultiCommand; } } private void SelectedMultiCommandExecuted(object obj) { System.Collections.IList tempIList = obj as System.Collections.IList; if (tempIList != null && tempIList.Count > 0) { SelectedBooksCollection = new ObservableCollection<Book>(); foreach (var item in tempIList) { Book tempBk = item as Book; if(tempBk != null) { SelectedBooksCollection.Add(tempBk); } } } //StringBuilder builder = new StringBuilder(); //foreach (var item in SelectedBooksCollection) //{ // builder.AppendLine($"{item.Id},{item.Name}"); //} //System.Windows.MessageBox.Show($"Selected {SelectedBooksCollection.Count} items","Information",MessageBoxButton.OK,MessageBoxImage.Information); } } public class Book { public int Id { get; set; } public string Name { get; set; } public string ISBN { get; set; } public string Title { get; set; } } public class DelegateCmd : ICommand { private readonly Action<object> _execute; private readonly Predicate<object> _canExecute; public DelegateCmd(Action<object> executeValue, Predicate<object> canExecuteValue) { _execute = executeValue; _canExecute = canExecuteValue; } public DelegateCmd(Action<object> executeValue) : this(executeValue, null) { } public event EventHandler CanExecuteChanged; public void RaiseCanExecuteChanged() { if (CanExecuteChanged != null) { CanExecuteChanged(this, EventArgs.Empty); } } public bool CanExecute(object parameter) { if (_canExecute == null) { return true; } return _canExecute(parameter); } public void Execute(object parameter) { _execute(parameter); } } }
The key contains two parts
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; namespace WpfApp39 { public class MultiSelectDataGrid:DataGrid { public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(IList), typeof(MultiSelectDataGrid), new PropertyMetadata(default(IList))); public new IList SelectedItems { get { return (IList)GetValue(SelectedItemsProperty); } set { throw new Exception("This property is read-only. To bind to it you must use 'Mode=OneWayToSource'."); } } protected override void OnSelectionChanged(SelectionChangedEventArgs e) { base.OnSelectionChanged(e); SetValue(SelectedItemsProperty, base.SelectedItems); } } } <Grid> <local:MultiSelectDataGrid x:Name="dg" ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectionMode="Extended" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderBrush="Blue" BorderThickness="5" SelectedItems="{Binding SelectedBooks,Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged}" > </local:MultiSelectDataGrid> </Grid> private IList selectedBooks; public IList SelectedBooks { get { return selectedBooks; } set { selectedBooks = value; if(selectedBooks!=null && selectedBooks.Count>0) { MessageBox.Show($"Selected {selectedBooks?.Count} items", "Multi Selected", MessageBoxButton.OK, MessageBoxImage.Information); } } }
referenced https://stackoverflow.com/questions/9880589/bind-to-selecteditems-from-datagrid-or-listbox-in-mvvm#