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?
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--; }
}