Search code examples
c#wpfmvvmdatagrid

What is the correct way to get the selected rows count using mvvm and c#?


In my WPF app I have a datagrid like

<DataGrid
                SelectedItem="{Binding SelItm, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                ItemsSource="{Binding FilteredStudents}"
                SelectionMode="Extended"
                AutoGenerateColumns="False"
                IsReadOnly="True"
                SelectionUnit="FullRow"
                HeadersVisibility="Column"
                <DataGrid.Columns>
                    <DataGridTextColumn
                        Header="Bill No."
                        Binding="{Binding Path=Name, Mode=OneWay}"
                        Width="260"
                        IsReadOnly="True" />
                    <DataGridTextColumn
                        Header="Bill Date"
                        Binding="{Binding Path=Address, Mode=OneWay}"
                        Width="200"
                        IsReadOnly="True" />
                    <DataGridTextColumn
                        Header="Amount"
                        Binding="{Binding Path=Age, Mode=OneWay}"
                        Width="210"
                        IsReadOnly="True" />
                </DataGrid.Columns>
            </DataGrid>

The itemsource of the datagrid is an ICollectionView called FilteredStudents. I've created a property selrows in my viewmodel which I binded to a label to display the selected rows count using like selrows = SelItm.Count();.

    private ICollectionView _allFilteredStudents;
    public ICollectionView FilteredStudents
    {
        get
        {
            if(_allFilteredStudents == null)
            {
                this._allFilteredStudents = new ListCollectionView(GetAllStudents)
                {
                    Filter = o => ((Students)o).Name != "Ram"
                };
            }
            return _allFilteredStudents;
        }
    }

But it is displaying incorrect result.

BTW, my database looks like

enter image description here

What is the proper way to get the selected rows count of a WPF datagrid following mvvm pattern?


Solution

  • Here is the solution:

    If you are going to show the number of the selected row in the view, simply choose a name for the grid and bind to SelectedItems.Count of the grid.

    In order to access selected items count in your c# code, you can add a IsSelected property to the StudentModel and bind it to the row's IsSelected attribute using RowStyle. This way whenever a row is selected/unselected, the IsSelected property of the StudentModel will be updated in the code and you can find selected students using that proertry like this FilteredStudents.Cast<StudentModel>().Count(i => i.IsSelected)

    <Grid>
         <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Button Content="GetSelectedRowsCount" Command="{Binding ButtonCommand}"/>
        <TextBlock Grid.Row="1" Text="{Binding ElementName=grid, Path=SelectedItems.Count}"/>
        <DataGrid Grid.Row="2" x:Name="grid"
                ItemsSource="{Binding FilteredStudents}"
                SelectionMode="Extended"
                AutoGenerateColumns="False"
                IsReadOnly="True"
                SelectionUnit="FullRow"
                HeadersVisibility="Column" >
            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Setter Property="IsSelected" Value="{Binding Path = IsSelected}"/>
                </Style>
            </DataGrid.RowStyle>
            <DataGrid.Columns>
                <DataGridTextColumn Header="Id" Binding="{Binding Path=Id, Mode=OneWay}"/>
                <DataGridTextColumn Header="Name" Binding="{Binding Path=Name, Mode=OneWay}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
    

    Now there is a IsSelected property in your StudentModel you can find how many rows are selected by filtering the collection in your code.

    Here is the student model:

    public class StudentModel : Notifier
    {
        private int _id;
        public int Id
        {
            get { return _id; }
            set
            {
                this._id = value;
                RaisePropertyChanged();
            }
        }
    
        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                this._name = value;
                RaisePropertyChanged();
            }
        }
    
        private bool _isSelected;
        public bool IsSelected
        {
            get { return _isSelected; }
            set
            {
                this._isSelected = value;
                RaisePropertyChanged();
            }
        }
    }
    

    and this is the viewModel:

    public class AppPresenter : Notifier
    {
        private ICollectionView _allFilteredStudents;
        public ICollectionView FilteredStudents
        {
            get
            {
                if (_allFilteredStudents == null)
                {
                    this._allFilteredStudents = new ListCollectionView(GetAllStudents())
                    {
                        Filter = o => ((StudentModel)o).Name != "Ram"
                    };
                }
                return _allFilteredStudents;
            }
        }
    
        public List<StudentModel> GetAllStudents()
        {
            return new List<StudentModel>()
            {
                new StudentModel(){ Id=1, Name="name1"},
                new StudentModel(){ Id=2, Name="name2"},
                new StudentModel(){ Id=3, Name="name3"},
                new StudentModel(){ Id=4, Name="name4"},
            };
        }
    
    
    public int GetSelectedRowCount()
    {
        var selrows = FilteredStudents.Cast<StudentModel>().Count(i => i.IsSelected);
    
        return selrows;
    }
    
    
    private RelayCommand _buttonCommand;
    
    public RelayCommand ButtonCommand
    {
        get
        {
            if (_buttonCommand == null)
            {
                _buttonCommand = new RelayCommand(param => this.GetSelectedRowCount());
            }
    
            return _buttonCommand;
        }
    }
         
    }
    

    Finally this is the MainWindow.cs

    public MainWindow()
    {
        InitializeComponent();
    
        this.DataContext = new AppPresenter();
    }