2

I'm trying to figure out how to bind a button to select all the rows(items) in a DataGrid using MVVM(Caliburn.Micro).

I'm looking to have this button be separate from the DataGrid itself.

Something like:

View:

<Button x:Name="SelectAll"/>

<DataGrid x:Name="People">

    <DataGrid.RowStyle>
        <Style>
            <Setter Property="DataGridRow.IsSelected"
                    Value="{Binding IsPersonSelected}" />
        </Style>
    </DataGrid.RowStyle>

    <DataGrid.Columns>
        <DataGridTextColumn Header="Name"
                            Binding="{Binding PersonName, UpdateSourceTrigger=PropertyChanged}" />
     </DataGrid.Columns>

</DataGrid>

ViewModel:

public bool _isPersonSelected = false;

public bool IsPersonSelected
{
    get { return _isPersonSelected; }
    set 
    { 
        _isPersonSelected = value;
        NotifyOfPropertyChange(() => IsPersonSelected);
    }
}

public void SelectAll()
{
    if(IsPersonSelected == true)
    {
        IsPersonSelected = false;
    }
    else
    {
        IsPersonSelected = true;
    }
}

This doesn't work though, perhaps there is another way of selecting rows in a DataGrid using some sort of binding for MVVM?

Or some way of calling the SelectAllCommand RoutedUICommand for DataGrids?

Suggestions/help would be greatly appreciated.

Corey
  • 835
  • 1
  • 9
  • 32
  • Quick google found this little gem https://stackoverflow.com/a/22908694/5233410 – Nkosi May 19 '20 at 16:06
  • While that is a bit old and probably outdated You could consider populating the `SelectedItems` property – Nkosi May 19 '20 at 16:10
  • @Nkosi Though this does solve some things that I was going to look into in the future, it, unfortunately, does not quite solve it for me. This does the opposite of what I'm trying to figure out. This tells me what is selected after I select rows. But I need something that selects all the rows for me. – Corey May 19 '20 at 20:15
  • @Nkosi Also, I tried using the `SelectedItems` property, but that's a `read only` property, so unfortunately I won't be able to populate that. – Corey May 19 '20 at 20:45
  • without your complete code wpf C#, i have proposed a solution to trap the selected rows and to have the possibility to change the selection (by using a boolean). So the selection is modyfiable as you wanted. – Frenchy May 20 '20 at 17:58

1 Answers1

1

I dont see your definition of Class and Model, so i suppose you have IsPersonSelected is property of your class ? have you try

public class PersonModel:PropertyChangedBase
{
    :
    :
    public bool IsPersonSelected
    {
        get => _isPersonSelected;
        set
        {
            _isPersonSelected = value;
            NotifyOfPropertyChange(() => IsPersonSelected);
        }
    }
}

<DataGrid.RowStyle>
    <Style TargetType="{x:Type DataGridRow}">
        <Setter Property="IsSelected"  Value="{Binding IsPersonSelected, Mode=TwoWay}"/>
    </Style>
</DataGrid.RowStyle>

after with SelectAll()

you do :

    public  void SelectAll()
   {
           foreach(var p in People)
              if(p.IsPersonSelected)
                    //DO something
      {

If you select multiples rows, you could see the value at true for this row After you could change the selection by modifying the value of IsPersonSelected, but that dont highlight the corresponding rows of datagrid, the property IsSelected doesnt reproduce the highlight of rows selected, to do that, its another problem (using VisualHelper). To reproduce the Highlight of rows selected by program, it is little more complex and need to change your coding and need to have your complete code wpf.


Another way to select multiple rows without using the property IsSelected:

add xmlns:cal="http://www.caliburnproject.org"

    <DataGrid x:Name="People" cal:Message.Attach="[Event SelectionChanged] = [Row_SelectionChanged($eventArgs)]">

in your viewmodel:

    public void Row_SelectionChanged(SelectionChangedEventArgs obj)
    {
        //(obj.OriginalSource as DataGrid).SelectedIndex gives you the index of row selected
        _selectedObjects.AddRange(obj.AddedItems.Cast<PersonModel>());
        obj.RemovedItems.Cast<PersonModel>().ToList().ForEach(w => _selectedObjects.Remove(w));
    }
    List<PersonModel> _selectedObjects = new List<PersonModel>();
    public PersonModel SelectedPeople { get; set; } //Will be set by Caliburn Micro automatically (name convention)

each time you select a row, it is added to the list, with ctrl you could add more rows or unselect one. Each event modifies the content of list.. (sorry for my english, hope you understant). FYI, using caliburn you have access to the name convention, so like your datagrid is named People, automatically the first row selected is binded to SelectedPeople

Frenchy
  • 16,386
  • 3
  • 16
  • 39
  • I don't have a property for if they are selected. Is this really the only way? Seems silly to save a selected state in the database. – Corey May 20 '20 at 19:37
  • Do you know why this works by setting the property to the model and not a property in the viewmodel? – Corey May 20 '20 at 20:45
  • i have just followed your logic you wanted to use a boolean to record the selected rows... but you dont take the right way, how do you want record lot of selected rows with just one boolean variable?.you need a collection at minimal. So you dont need to add a boolean to follow the selected rows but i dont know what you want exactly? i have just resolved your problem . i have understood you want to select the row by program is right? do you want highlight too? is not the same thing – Frenchy May 20 '20 at 21:52
  • see my answer modified to use another way to trap selectedRows with a collection inside the viewmodel, no need to use a bolean in the model, and you could put off the use of property IsSelected – Frenchy May 20 '20 at 22:09