Search code examples
c#wpfxamlmvvmdatagrid

Select multiple items from a DataGrid in an MVVM WPF project


How can I select multiple items from a DataGrid in an MVVM WPF project?


Solution

  • 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.