How can I select multiple items from a DataGrid
in an MVVM WPF project?
9 Answers
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.
-
I tried your code and it works fine when it is selecting the multiple rows but when I implement a delete function, it causes an exception. can you please see this link http://stackoverflow.com/questions/29675086/collection-was-modified-when-trying-to-remove-selected-items-of-datagrid – Emil Apr 16 '15 at 13:55
-
1Looks like you got your answer :) – Sandesh Apr 17 '15 at 03:26
-
This would not work if you want to check if the new selected items list equals the previous in your setter of TestSelected. The reason is that both SelectedItemsList and SelectedItemseason in CustomDataGrid_SelectionChanged contain the same reference to the list. So they will always be equal. – tabina Sep 10 '15 at 11:38
-
@tabina You are right that this solution is useful only when you want to get all the __currently__ selected items and is of no use if you want to compare it with old selected items. What you can do is modify the `PropertyMetadata` of the Dependency Property to include a function which can do the comparison – Sandesh Sep 11 '15 at 05:47
-
I've made an attached property `local:SelectedItems` so I do not need to subclass the `DataGrid`. – xmedeko Apr 08 '16 at 15:38
-
12`this.SelectedItemsList = this.SelectedItems;` did not work for me, as `SelectedItemsList` was always set to `null`. However, changing the code to `foreach (var item in this.SelectedItems) { this.SelectedItemsList.Add(item); }` did the trick. Please note, that this requires you to call `this.SelectedItemsList.Clear();` in advance, so the items of `SelectedItemsList` will not get duplicated. – M463 Apr 18 '16 at 09:32
-
1Why do u have TwoWay binding of SelectedItemsList? I dont think your code can handle changing the SelectedItems property from its Source (VM). – Lukáš Koten Sep 18 '17 at 19:38
-
is there a way to bind it to a typed list? so instead of IList SelectedModel bind to a property of type List
– Sjors Miltenburg Nov 24 '17 at 08:48 -
@sjorsmiltenburg just do it like M463 suggested, add the items to the existing list, then it also works with typed lists. – Coden Mar 26 '20 at 13:01
-
Why `TwoWay` if you cannot set the Grid's `SelectedItems`? – Daniel Möller Jun 11 '21 at 01:06
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.

- 10,565
- 4
- 43
- 72
-
-
@MegaMind I am trying to emphasize that you won't need SelectionChanged event when you used behaviors. – 123 456 789 0 Apr 04 '15 at 01:50
-
1@III I have tried your solution, but in view model, selected items always remains null. I have compiled a simple solution depicting your code. If you could take a look at that. https://www.dropbox.com/s/lh4zrhnatpchqzi/MultiSelectedDataGrid.zip?dl=0 – Manvinder Apr 04 '15 at 04:50
-
-
-
2@III - Yes, silly me, I referenced the same answer. I can't edit my bad comment now so I've deleted it - THIS was the one that worked for me: http://stackoverflow.com/a/8088926 . As I said in my old comment (now deleted), your answer didn't work for me, SelectedItems is always null, like for MegaMind. The other answer is almost the same as yours, and it works for me. – Edward Mar 24 '16 at 23:09
-
`DataGrid` HAS a `SelectedItems` property, but it's not a dependency property so binding does not work. > doesn't expose `SelectedItems` is a wrong statement. – Maxence Jan 31 '18 at 17:03
-
1As long as `SelectedItems` is of type `IEnumerable` I also got `null`. But as soon as the type was changed to `IList` the data came. Unfortunately the Binding was not really TwoWay. The solution was a combination between this answer and this [blog entry](https://www.tyrrrz.me/Blog/WPF-ListBox-SelectedItems-TwoWay-binding) – Raphael Müller Feb 20 '18 at 13:34
-
Just repeating @RaphaelMüller comment above: for actually working `TwoWay` binding you can use the solution from [WPF ListBox SelectedItems TwoWay Binding](https://tyrrrz.me/blog/wpf-listbox-selecteditems-twoway-binding). I've just copied and it worked, not combined anything at all in my case. – Brains Mar 06 '20 at 17:06
I use this solution in my app:
XAML:
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectItemsCommand}" CommandParameter="{Binding Path=SelectedItems,ElementName=TestListView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
at the top of you xaml file, add this line of code:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
SelectedItemsCommand is ICommand type which is written in your viewmodel.
Used DLL:
System.Windows.Interactivity.dll

- 2,094
- 3
- 26
- 66
With the default DataGrid
of WPF it is not possible to use a Binding, as it is possible with the SelectedItem
-Property, cause the SelectedItems
-Property is not a DependencyProperty.
One way to to what you want is to register the SelectionChanged
-Event of the DataGrid to update the property of your ViewModel, that stores the selected items.
The property SelectedItems of the DataGrid is of type IList so you need to cast the items in the list to your specific type.
C#
public MyViewModel {
get{
return this.DataContext as MyViewModel;
}
}
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) {
// ... Get SelectedItems from DataGrid.
var grid = sender as DataGrid;
var selected = grid.SelectedItems;
List<MyObject> selectedObjects = selected.OfType<MyObject>().ToList();
MyViewModel.SelectedMyObjects = selectedObjects;
}
XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid
SelectionChanged="DataGrid_SelectionChanged"
/>
</Grid>
</Window>

- 34,674
- 10
- 123
- 155
-
1Thanks for your answer but I am looking for something pure MVVM based and that should not involved code behind – Manvinder Apr 07 '14 at 10:26
-
I appreciate this answer. Even though it's not MVVM it's the first one to mention _why_ I can't access the `SelectedItems` property in XAML. – Steffen Winkler Apr 11 '17 at 08:59
-
2And it doesn't corrupt your MVVM model at all. You still have a pure SelectedMyObjects property in your VM that knows nothing about the View or how it gets set. Just having some code in the View doesn't mean it's not pure MVVM. – Bill Lefler May 04 '17 at 18:40
You can add the "IsSelected" property in the Model and add a checkBox in the row.

- 1,490
- 2
- 22
- 35
You can maka a reusable generic base class. This way you can select rows both from code and UI.
This is my example class i want to be selectable
public class MyClass
{
public string MyString {get; set;}
}
Make generic base class for selectable classes. INotifyPropertyChanged makes the UI update when you set IsSelected.
public class SelectableItem<T> : System.ComponentModel.INotifyPropertyChanged
{
public SelectableItem(T item)
{
Item = item;
}
public T Item { get; set; }
bool _isSelected;
public bool IsSelected {
get {
return _isSelected;
}
set {
if (value == _isSelected)
{
return;
}
_isSelected = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("IsSelected"));
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
}
Create selectable class
public class MySelectableItem: SelectableItem<MyClass>
{
public MySelectableItem(MyClass item)
:base(item)
{
}
}
Create property to bind to
ObservableCollection<MySelectableItem> MyObservableCollection ...
Set propety
MyObservableCollection = myItems.Select(x => new MySelectableItem(x));
Bind to datagrid and add a style on the DataGridRow that binds to the IsSelected propety on the MySelectedItem
<DataGrid
ItemsSource="{Binding MyObservableCollection}"
SelectionMode="Extended">
<DataGrid.Resources>
<Style TargetType="DataGridRow">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
</DataGrid.Resources>
</DataGrid>
To get selected rows/items
var selectedItems = MyObservableCollection.Where(x=>x.IsSelected).Select(y=>y.Item);
To select rows/items
MyObservableCollection[0].IsSelected = true;
Edit———> It seems like it does not work when EnableRowVirtualization is true

- 1,104
- 2
- 15
- 26
-
Unfortunately, this did not work reliably for me when rows that are currently not visible (because they are scrolled out of view) get selected or deselected. – Martin Jan 02 '18 at 14:40
-
It seems like it does not work when EnableRowVirtualization is true – AxdorphCoder Jan 03 '18 at 16:08
WPF DataGrid allows for this.
Simply set the DataGrid.Rows.SelectionMode and DataGrid.Rows.SelectionUnit to "Extended" and "CellOrRowHeader" respectively. This can be done in Blend, as shown in the image I have included. This will allow user to select each cell, whole rows etc. as many as they like, using either shift or ctrl key to continue selecting.

- 674
- 4
- 8
-
3the problem is that you won't be able to access the selected data in a MVVM project. – Steffen Winkler Apr 11 '17 at 09:01
The project I'm working on uses MVVM Light and I found this blog post to be the simplest solution. I'll repeat the solution here:
View Model:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
...
public class SomeVm : ViewModelBase {
public SomeVm() {
SelectItemsCommand = new RelayCommand<IList>((items) => {
Selected.Clear();
foreach (var item in items) Selected.Add((SomeClass)item);
});
ViewCommand = new RelayCommand(() => {
foreach (var selected in Selected) {
// todo do something with selected items
}
});
}
public List<SomeClass> Selected { get; set; }
public RelayCommand<IList> SelectionChangedCommand { get; set; }
public RelayCommand ViewCommand { get; set; }
}
XAML:
<Window
...
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:command="http://www.galasoft.ch/mvvmlight"
...
<DataGrid
Name="SomeGrid"
...
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<command:EventToCommand
Command="{Binding SelectionChangedCommand}"
CommandParameter="{Binding SelectedItems, ElementName=SomeGrid}" />
</i:EventTrigger>
</i:Interaction.Triggers>
...
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="View" Command="{Binding ViewCommand}" />
</ContextMenu>
</DataGrid.ContextMenu>
...

- 5,350
- 4
- 41
- 44
-
Your code is confusing because in the VM your Command is called SelectionChangedCommand when it's initialised but SelectItemsCommand when it's declared. – Joren Vandamme Jun 01 '23 at 20:04
My solution is almost a same like Sandesh. On the other hand, I did not use CustomDataGrid to solve this problem. Instead of that I used a plus button click event with the proper function in a viewmodel. In my code, the main point was that to be able to delete more than one person object from the Datagrid wich was bind to the PeopleList property (ObservableCollection)
This is my Model:
public class Person
{
public Person()
{
}
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
}
This is my ViewModel (only thoose parts, which are necessary):
public class PersonViewModel : BindableBase
{
private ObservableCollection<Person> _peopleList;
// to be able to delete or save more than one person object
private List<Person> _selectedPersonList;
//MyICommand
public MyICommand AddCommand { get; set; }
public MyICommand DeleteCommand { get; set; }
private string _firstName;
private string _lastName;
private int _age;
public PersonViewModel()
{
_peopleList = new ObservableCollection<Person>();
LoadPerson();
AddCommand = new MyICommand(AddPerson);
DeleteCommand = new MyICommand(DeletePerson, CanDeletePerson);
// To be able to delete or save more than one person
_selectedPersonList = new List<Person>();
}
public ObservableCollection<Person> PeopleList
{
get { return _peopleList; }
set
{
_peopleList = value;
RaisePropertyChanged("PeopleList");
}
}
public List<Person> SelectedPersonList
{
get { return _selectedPersonList; }
set
{
if (_selectedPersonList != value)
{
RaisePropertyChanged("SelectedPersonList");
}
}
}
private void DeletePerson()
{
// to be able to delete more than one person object
foreach (Person person in SelectedPersonList)
{
PeopleList.Remove(person);
}
MessageBox.Show(""+SelectedPersonList.Count); // it is only a checking
SelectedPersonList.Clear(); // it is a temp list, so it has to be cleared after the button push
}
public void GetSelectedPerson(DataGrid datagrid)
{
IList selectedItems = datagrid.SelectedItems;
foreach (Person item in selectedItems)
{
SelectedPersonList.Add(item);
}
}
My View (xmal):
<UserControl x:Class="DataBase.Views.PersonView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:DataBase.Views"
xmlns:viewModel="clr-namespace:DataBase.ViewModels" d:DataContext="{d:DesignInstance Type=viewModel:PersonViewModel}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" Background="AliceBlue">
<TextBlock Text="First Name:"/>
<TextBox x:Name="firstNameTxtBox" Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="Last Name:"/>
<TextBox x:Name="lastNameTxtBox" Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="Age:"/>
<TextBox x:Name="ageTxtBox" Text="{Binding Age}"/>
<TextBlock Text="{Binding FullName}"/>
<Button Content="Add" IsEnabled="{Binding CanAddPerson}" Command="{Binding AddCommand}"/>
<Button Content="Delete" Command="{Binding DeleteCommand}" Click="Delete_Click"/>
<DataGrid x:Name="datagridPeopleList" ItemsSource="{Binding PeopleList}" AutoGenerateColumns="True" SelectedItem="{Binding SelectedPerson}" SelectionMode="Extended" SelectionUnit="FullRow"/>
<!--<ListView Height="50" ItemsSource="{Binding PeopleList}" SelectedItem="{Binding SelectedPerson}" Margin="10">
</ListView>-->
</StackPanel>
</Grid>
</UserControl>
My View (.cs):
public partial class PersonView : UserControl
{
public PersonViewModel pvm;
public PersonView()
{
pvm = new PersonViewModel();
InitializeComponent();
DataContext = pvm;
}
private void Delete_Click(object sender, RoutedEventArgs e)
{
pvm.GetSelectedPerson(datagridPeopleList);
}
}
I hope that it is useful and not the worst (non elegant) solution in the world :D

- 1