#StackBounty: #wpf #mvvm #datagrid #viewmodel Custom WPF DataGrid to select one or multiple rows manually from ViewModel

Bounty: 50

I try to create a DataGrid for WPF / MVVM which allows to manually select one ore more items from ViewModel code.

As usual the DataGrid should be able to bind its ItemsSource to a List / ObservableCollection. The new part is that it should maintain another bindable list, the SelectedItemsList. Each item added to this list should immediately be selected in the DataGrid.

I found this solution on Stackoverflow: There the DataGrid is extended to hold a Property / DependencyProperty for the SelectedItemsList:

public class CustomDataGrid : DataGrid
{
  public CustomDataGrid()
  {
    this.SelectionChanged += CustomDataGrid_SelectionChanged;
  }

  private void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
  {
    this.SelectedItemsList = this.SelectedItems;
  }

  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));
}

In the View/XAML this property is bound to the ViewModel:

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="Auto"/>
  </Grid.RowDefinitions>
  <ucc:CustomDataGrid Grid.Row="0" 
                      ItemsSource="{Binding DataGridItems}"
                      SelectionMode="Extended"
                      AlternatingRowBackground="Beige"
                      SelectionUnit="FullRow"
                      IsReadOnly="True"
                      SelectedItemsList="{Binding DataGridSelectedItems, 
                                          Mode=TwoWay,
                                          UpdateSourceTrigger=PropertyChanged}" />

  <Button Grid.Row="1"
        Margin="5"
        HorizontalAlignment="Center"
        Content="Select some rows"
        Command="{Binding CmdSelectSomeRows}"/>

</Grid>

The ViewModel also implements the command CmdSelectSomeRows which selects some rows for testing. The ViewModel of the test application looks like this:

public class CustomDataGridViewModel : ObservableObject
{
  public IList DataGridSelectedItems
  {
    get { return dataGridSelectedItems; }
    set
    {
      dataGridSelectedItems = value;
      OnPropertyChanged(nameof(DataGridSelectedItems));
    }
  }

  public ICommand CmdSelectSomeRows { get; }

  public ObservableCollection<ExamplePersonModel> DataGridItems { get; private set; }



  public CustomDataGridViewModel()
  {
    // Create some example items
    DataGridItems = new ObservableCollection<ExamplePersonModel>();

    for (int i = 0; i < 10; i++)
    {
      DataGridItems.Add(new ExamplePersonModel
      {
        Name = $"Test {i}",
        Age = i * 22
      });
    }

    CmdSelectSomeRows = new RelayCommand(() =>
    {
      if (DataGridSelectedItems == null)
      {
        DataGridSelectedItems = new ObservableCollection<ExamplePersonModel>();
      }
      else
      {
        DataGridSelectedItems.Clear();
      }

      DataGridSelectedItems.Add(DataGridItems[0]);
      DataGridSelectedItems.Add(DataGridItems[1]);
      DataGridSelectedItems.Add(DataGridItems[4]);
      DataGridSelectedItems.Add(DataGridItems[6]);
    }, () => true);
  }
  
  
  
  private IList dataGridSelectedItems = new ArrayList();
}

This works, but only partially: After application start when items are added to the SelectedItemsList from ViewModel, they are not displayed as selected rows in the DataGrid. To get it to work I must first select some rows with the mouse. When I then add items to the SelectedItemsList from ViewModel these are displayed selected – as I want it.

How can I achieve this without having to first select some rows with the mouse?


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.