Search code examples
c#wpfmvvmdatagridcaliburn.micro

Can't Select All in DataGrid when Clicking Button in WPF Caliburn.Micro


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.


Solution

  • 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