WPF。通过 MultiBinding 更改 CheckBox IsChecked 不会触发 CheckBox 命令
WPF. Changing CheckBox IsChecked through MultiBinding doesn't triger CheckBox Command
我的 WPF 应用程序视图中有数据网格,我在 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>
如您所见,我将 CheckBox 属性 "IsSelected" 绑定到多个值,其中之一是 DataGrid 行选择:
<Binding Path="IsSelected"
Mode="OneWay"
RelativeSource="{RelativeSource FindAncestor,
AncestorType={x:Type DataGridRow}}"
/>
我的问题是 - 当我通过选择行选中 CheckBox 时,链接到 CheckBox 的命令没有被触发。但是当我手动(使用鼠标)时它会触发。我该如何解决?
根据 CheckBox 源代码,不支持所需的方法 - 只有在单击后才会调用命令。
但是,您可以创建一个小的 CheckBox 后代来实现您需要的行为。此后代将跟踪 CheckBox.IsChecked
属性 的更改并执行命令。
你可以这样做:
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();
}
}
}
还有储物柜class:
class Locker : IDisposable {
int count = 0;
public bool IsLocked { get { return count != 0; } }
public IDisposable Lock() {
count++;
return this;
}
public void Dispose() { count--; }
}
我的 WPF 应用程序视图中有数据网格,我在 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>
如您所见,我将 CheckBox 属性 "IsSelected" 绑定到多个值,其中之一是 DataGrid 行选择:
<Binding Path="IsSelected"
Mode="OneWay"
RelativeSource="{RelativeSource FindAncestor,
AncestorType={x:Type DataGridRow}}"
/>
我的问题是 - 当我通过选择行选中 CheckBox 时,链接到 CheckBox 的命令没有被触发。但是当我手动(使用鼠标)时它会触发。我该如何解决?
根据 CheckBox 源代码,不支持所需的方法 - 只有在单击后才会调用命令。
但是,您可以创建一个小的 CheckBox 后代来实现您需要的行为。此后代将跟踪 CheckBox.IsChecked
属性 的更改并执行命令。
你可以这样做:
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();
}
}
}
还有储物柜class:
class Locker : IDisposable {
int count = 0;
public bool IsLocked { get { return count != 0; } }
public IDisposable Lock() {
count++;
return this;
}
public void Dispose() { count--; }
}