Search code examples
c#wpfmvvmcheckboxdatagrid

Update Checkbox of Selected Rows in Datagrid


WPF beginner here with what is probably a really simple question. Is possible to to select multiple rows and check the checkbox of all selected?

I would like selected S601 & S701 boxes to check when S501 is checked

Code:

        public string drawingNumber { get; set; }

        bool isChecked;

        bool isSelected;

        public bool IsSelected
        {
            
            get { return this.isSelected; }
            set { this.Set(() => IsSelected, ref isSelected, value); }
        } 
     
        public bool IsChecked
        {
            get { return this.isChecked; }
            set {
                    this.Set(() => IsChecked, ref isChecked, value);
            }
        }

Bindings:

        <DataGrid  ItemsSource="{Binding MyListCollection}" SelectionMode="Extended" AutoGenerateColumns="False" HorizontalAlignment="Stretch" CanUserSortColumns="False" FrozenColumnCount="0" CanUserResizeRows="False" CanUserDeleteRows="False" HeadersVisibility="Column" Padding="0" GridLinesVisibility="Horizontal">
            <DataGrid.ColumnHeaderStyle >
                <Style TargetType="DataGridColumnHeader">
                    <Setter Property="Background" Value="#abf299"></Setter>
                    <Setter Property="Typography.Capitals" Value="AllSmallCaps"></Setter>
                    <Setter Property="FontFamily" Value="ArialNarrow"></Setter>
                </Style>
            </DataGrid.ColumnHeaderStyle>
            <DataGrid.Columns>
                <DataGridTextColumn x:Name="dataGridTextColumn" Header="Number" Binding="{Binding drawingNumber}"  IsReadOnly="True" Width="*" MinWidth="100" />
                <DataGridTemplateColumn Header="Selection">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
            <DataGrid.RowStyle>
                <Style TargetType="{x:Type DataGridRow}">
                    <Setter Property="IsSelected" Value="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>

Solution

  • I tried using RelayCommand and come up with this solution:

    1. You missed property changed for a property drawingNumber. I assume that this.Set is for that, so:
    private string drawingNumber;
    public string DrawingNumber { get => drawingNumber; set { drawingNumber = value; this.Set(() => DrawingNumber, ref drawingNumber, value); } }
    
    1. You need to make some small adjustments in XAML code:
        ...
    <Window.DataContext>
        <viewModel:MainWindowViewModel />
    </Window.DataContext>
    <StackPanel>
        <DataGrid  ...
                <DataGridTemplateColumn Header="Selection">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding Path=IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                      Command="{Binding Path=DataContext.UpdateCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                                      />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
    
                </DataGridTemplateColumn>
            </DataGrid.Columns>
            <DataGrid.RowStyle>
                <Style TargetType="{x:Type DataGridRow}">
                    <Setter Property="IsSelected" Value="{Binding Path=IsSelected,  UpdateSourceTrigger=PropertyChanged}"/>
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>
    
        <Button Content="Reset checkboxes" Command="{Binding Path=ResetCommand}" />
    </StackPanel>
    
    1. Here you need to implement ICommand to use RelayCommand to check if CheckBoxes are pressed (or you can use for example nuget package: CommunityToolkit.Mvvm which already implements RelayCommand and much more...)
    • Here is the code for a simple RelayCommand:
        public class RelayCommand : ICommand
        {
            private readonly Action<object> _execute;
            private readonly Predicate<object> _canExecute;
            public RelayCommand(Action<object> execute) : this(execute, param => true) { }
            public RelayCommand(Action<object> execute, Predicate<object> canExecute)
            {
                if (execute == null)
                    throw new ArgumentNullException("Invalid action");
                this._execute = execute;
                this._canExecute = canExecute;
            }
            public event EventHandler? CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
            public bool CanExecute(object parameter)
            {
                return this._canExecute == null ? true : _canExecute(parameter);
            }
            public void Execute(object parameter)
            {
                this._execute(parameter);
            }
        }
    
    • And here is the main code:
    public class MainWindowViewModel
    {
        public ObservableCollection<Item> MyListCollection { get; private set; }
    
        public MainWindowViewModel()
        {
            UpdateCommand = new RelayCommand(x => UpdateCheckBoxes());
            ResetCommand = new RelayCommand(x => ResetCheckBoxes());
    
            MyListCollection = new();
            MyListCollection.Add(new() { DrawingNumber = "S201", IsChecked = false });
            MyListCollection.Add(new() { DrawingNumber = "S501", IsChecked = true });
            MyListCollection.Add(new() { DrawingNumber = "S601", IsChecked = false });
            MyListCollection.Add(new() { DrawingNumber = "S701", IsChecked = false });
            MyListCollection.Add(new() { DrawingNumber = "S801", IsChecked = false });
            MyListCollection.Add(new() { DrawingNumber = "S901", IsChecked = true });
        }
    
        public ICommand UpdateCommand { get; private set; }
        public ICommand ResetCommand { get; private set; }
    
        public void UpdateCheckBoxes()
        {
            foreach (var item in MyListCollection)
            {
                if (item.IsSelected)
                    item.IsChecked = true;
                //else
                    //item.IsChecked = false;
            }
        }
    
        public void ResetCheckBoxes()
        {
            foreach (var item in MyListCollection)
            {
                item.IsChecked = false;
            }
        }
    }
    
    1. If you want to uncheck the checkbox, press ctrl+left mouse on that checkbox

    Hopefully somehow usable code for you