How can I select multiple items from a DataGrid in an MVVM WPF project?
A Grid is a control for laying out other controls on the form (or page). A DataGrid is a control for displaying tabular data as read from a database for example.
WPF DataGrid (SfDataGrid) provides built-in row called AddNewRow. It allows user to add a new row to underlying collection. You can enable or disable by setting SfDataGrid.
A DataGrid is a control that displays data in a customizable grid. It provides a flexible way to display a collection of data in rows and columns. The hierarchical inheritance of DataGrid class is as follows −
You can simply add a custom dependency property to do this:
public class CustomDataGrid : DataGrid {     public CustomDataGrid ()     {         this.SelectionChanged += CustomDataGrid_SelectionChanged;     }      void CustomDataGrid_SelectionChanged (object sender, SelectionChangedEventArgs e)     {         this.SelectedItemsList = this.SelectedItems;     }     #region SelectedItemsList      public IList SelectedItemsList     {         get { return (IList)GetValue (SelectedItemsListProperty); }         set { SetValue (SelectedItemsListProperty, value); }     }      public static readonly DependencyProperty SelectedItemsListProperty =             DependencyProperty.Register ("SelectedItemsList", typeof (IList), typeof (CustomDataGrid), new PropertyMetadata (null));      #endregion }   Now you can use this dataGrid in the XAML:
<Window x:Class="DataGridTesting.MainWindow"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"     xmlns:local="clr-namespace:DataGridTesting.CustomDatagrid"     Title="MainWindow"     Height="350"     Width="525">   <DockPanel>     <local:CustomDataGrid ItemsSource="{Binding Model}"         SelectionMode="Extended"         AlternatingRowBackground="Aquamarine"         SelectionUnit="FullRow"         IsReadOnly="True"         SnapsToDevicePixels="True"         SelectedItemsList="{Binding TestSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>   </DockPanel> </Window>   My ViewModel:
public class MyViewModel : INotifyPropertyChanged {     private static object _lock = new object ();     private List<MyModel> _myModel;      public IEnumerable<MyModel> Model { get { return _myModel; } }      private IList _selectedModels = new ArrayList ();      public IList TestSelected     {         get { return _selectedModels; }         set         {             _selectedModels = value;             RaisePropertyChanged ("TestSelected");         }     }      public MyViewModel ()     {         _myModel = new List<MyModel> ();         BindingOperations.EnableCollectionSynchronization (_myModel, _lock);          for (int i = 0; i < 10; i++)         {             _myModel.Add (new MyModel             {                 Name = "Test " + i,                 Age = i * 22             });         }         RaisePropertyChanged ("Model");     }      public event PropertyChangedEventHandler PropertyChanged;      public void RaisePropertyChanged (string propertyName)     {         var pc = PropertyChanged;         if (pc != null)             pc (this, new PropertyChangedEventArgs (propertyName));     } }   My model:
public class MyModel {     public string Name { get; set; }     public int Age { get; set; } }   And finally, here is the code behind of MainWindow:
public partial class MainWindow : Window {     public MainWindow ()     {         InitializeComponent ();         this.DataContext = new MyViewModel ();     } }   I hope this clean MVVM design helps.
What I would do is create Behaviors using System.Windows.Interactivity. You would have to reference it manually in your project.
Given a control which doesn't expose SelectedItems e.g., (ListBox, DataGrid)
You can create a behavior class something like this
public class ListBoxSelectedItemsBehavior : Behavior<ListBox> {     protected override void OnAttached()     {         AssociatedObject.SelectionChanged += AssociatedObjectSelectionChanged;     }      protected override void OnDetaching()     {         AssociatedObject.SelectionChanged -= AssociatedObjectSelectionChanged;     }      void AssociatedObjectSelectionChanged(object sender, SelectionChangedEventArgs e)     {         var array = new object[AssociatedObject.SelectedItems.Count];         AssociatedObject.SelectedItems.CopyTo(array, 0);         SelectedItems = array;     }      public static readonly DependencyProperty SelectedItemsProperty =         DependencyProperty.Register("SelectedItems", typeof(IEnumerable), typeof(ListBoxSelectedItemsBehavior),          new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));      public IEnumerable SelectedItems     {         get { return (IEnumerable)GetValue(SelectedItemsProperty); }         set { SetValue(SelectedItemsProperty, value); }     } }   And on your XAML I would do the Binding like this where i is xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" and behaviors is the namespace of your Behavior class
<ListBox>  <i:Interaction.Behaviors>     <behaviors:ListBoxSelectedItemsBehavior SelectedItems="{Binding SelectedItems, Mode=OneWayToSource}" />  </i:Interaction.Behaviors>     Assuming that your DataContext for the ListBox has the SelectedItems property in the ViewModel then it will automatically update the SelectedItems. You have encapsulated the event subscribing from the View i.e.,
<ListBox SelectionChanged="ListBox_SelectionChanged"/>   You can change the Behavior class to be of type DataGrid if you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With