wpfcheckboxdatagridcommandischecked

WPF. Changing CheckBox IsChecked through MultiBinding doesn't triger CheckBox Command


I have Datagrid in my WPF app view where I use check boxes in row headers.

<DataGrid.RowHeaderTemplate>
<DataTemplate>
    <Grid >
        <CheckBox BorderThickness="0"  
                  Command="{Binding DataContext.AssignPartsToGroupCommand, RelativeSource={RelativeSource FindAncestor,
                                                                               AncestorType={x:Type UserControl}}}"                                          
                                    >
            <CheckBox.CommandParameter>
                <MultiBinding Converter="{StaticResource PartsGroupAssignConverter}">
                    <Binding Path="IsChecked" RelativeSource="{RelativeSource Self}" Mode="OneWay"/>
                    <Binding RelativeSource="{RelativeSource Mode=FindAncestor, 
                                                             AncestorType={x:Type DataGridRow}}" 
                             Path="DataContext" Mode="OneWay"/>
                </MultiBinding>
            </CheckBox.CommandParameter>
            <CheckBox.IsChecked>
                <MultiBinding  Converter="{StaticResource PartsGroupAssignedConverter}"  Mode="OneWay">
                    <Binding ElementName="partsGroupGrid" Path="SelectedItem.id"></Binding>
                    <Binding RelativeSource="{RelativeSource Mode=FindAncestor, 
                                                             AncestorType={x:Type DataGridRow}}" 
                             Path="DataContext" Mode="OneWay"/>
                    <Binding Path="IsSelected" Mode="OneWay"
                             RelativeSource="{RelativeSource FindAncestor,
                              AncestorType={x:Type DataGridRow}}"
                             />
                </MultiBinding>
            </CheckBox.IsChecked>
        </CheckBox>
    </Grid>
</DataTemplate>

As you can see I bind CheckBox property "IsSelected" to multiple values and one of them is DataGrid row selection:

   <Binding Path="IsSelected" 
            Mode="OneWay"
            RelativeSource="{RelativeSource FindAncestor,
                                  AncestorType={x:Type DataGridRow}}"
                                 />

My problem is - the command linked to CheckBox is not triggered when I check CheckBox by selecting row. But it triggers when I do it manually (with mouse). How can I solve this?


Solution

  • According to the CheckBox source codes, the desired approach is not supported - a command will be called only after clicking on it.

    However, you can create a small CheckBox descendant to achieve the behavior you need. This descendant will track changes of the CheckBox.IsChecked property and execute a command.

    You can do it like this:

        public class MyCheckBox : CheckBox {
        static MyCheckBox() {
            IsCheckedProperty.OverrideMetadata(typeof(MyCheckBox), new FrameworkPropertyMetadata((o, e) => ((MyCheckBox)o).OnIsCheckedChanged()));
        }
    
        readonly Locker toggleLocker = new Locker();
        readonly Locker clickLocker = new Locker();
    
        void OnIsCheckedChanged() {
            if (clickLocker.IsLocked)
                return;
            using (toggleLocker.Lock()) {
                OnClick();
            }
        }
    
        protected override void OnToggle() {
            if (toggleLocker.IsLocked)
                return;
            base.OnToggle();
        }
    
        protected override void OnClick() {
            using (clickLocker.Lock()) {
                base.OnClick();
            }
        }
    }
    

    And the Locker class:

        class Locker : IDisposable {
        int count = 0;
        public bool IsLocked { get { return count != 0; } }
        public IDisposable Lock() {
            count++;
            return this;
        }
        public void Dispose() { count--; }
    }