CellTemplate中的DataTrigger绑定到HeaderTemplate;它可以工作吗?

时间:2011-08-30 15:44:22

标签: wpf datagrid datatrigger

此处的目标是在标题复选框更改时检查所有网格复选框:

<Window.Resources>

    <Style TargetType="CheckBox" x:Key="InnerBox">
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Style.Triggers>
            <DataTrigger Value="True"
                         Binding="{Binding IsChecked, 
                         ElementName=HeaderCheckbox}">
                <Setter Property="IsChecked" Value="True" />
            </DataTrigger>
            <DataTrigger Value="False"
                         Binding="{Binding IsChecked, 
                         ElementName=HeaderCheckbox}">
                <Setter Property="IsChecked" Value="False" />
            </DataTrigger>
        </Style.Triggers>
    </Style>

</Window.Resources>

<DataGrid>
    <DataGrid.Columns>

        <!-- col1 -->
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.HeaderTemplate>
                <DataTemplate>
                    <!-- header check -->
                    <CheckBox Name="HeaderCheckbox" />
                </DataTemplate>
            </DataGridTemplateColumn.HeaderTemplate>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <!-- body check -->
                    <CheckBox Style="{StaticResource InnerBox}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <!-- col2 -->
        <DataGridTextColumn Binding="{Binding}" Header="Text" />
    </DataGrid.Columns>

    <!-- sample data -->
    <sys:String>1</sys:String>
    <sys:String>2</sys:String>
    <sys:String>3</sys:String>
</DataGrid>

看起来像:

Screen

由于某种原因,触发器不会触发。

有什么想法吗?

2 个答案:

答案 0 :(得分:4)

正如您所注意到的,ElementName内{p> DataTemplate绑定无法到达模板外的元素。这是因为它可以多次实例化并具有自己的名称范围,因此您在ElementName内创建的任何DataTemplate绑定都将在模板内部查找具有该名称的另一个元素。

使用Snoop查看它我们也可以看到RelativeSource绑定不能直接使用,因为它们位于Visual Tree的不同部分

enter image description here

我能想到的唯一能解决这个问题的方法是将两个CheckBox绑定到一个共同的祖先,例如:父DataGrid并使用附加属性或Tag属性。实施例

<Style TargetType="CheckBox" x:Key="InnerBox">
    <Setter Property="HorizontalAlignment" Value="Center" />
    <Setter Property="IsChecked" Value="False" />
    <Style.Triggers>
        <DataTrigger Value="True"
                     Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
                                       Path=Tag}">
            <Setter Property="IsChecked" Value="True" />
        </DataTrigger>
    </Style.Triggers>
</Style>

<DataTemplate>
    <!-- header check -->
    <CheckBox Name="HeaderCheckbox"
              IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
                                  Path=Tag,
                                  Mode=OneWayToSource}"/>
</DataTemplate>

答案 1 :(得分:0)

我认为HeaderCheckBox的常规DataBinding不可能,因为CheckBox作为Template的一部分存在,并且它位于VisualTree的不同分支中比DataGridItems

通常我反过来说:当检查标题CheckBox时,检查所有行CheckBoxes。我的主要原因是因为CheckBoxes通常在那里,所以用户可以检查/取消选中它们,如果它们被绑定到CheckBox选中状态,那么用户就无法改变它们。

为了实现这一点,我通常会挂钩Header CheckBox的ClickChecked事件。

如果行CheckBox.IsChecked状态绑定到ViewModel中的某些内容,我会将事件挂钩到ViewModel中的Command,并设置CheckBox.IsCheckedtrue的数据项绑定到false / CommandParameter,具体取决于标题CheckBox状态(通常作为CheckBox.IsChecked传入)

如果DataGrid.Items状态没有绑定任何内容,您可以使用常规代码隐藏循环遍历ItemContainerGenerator,使用CheckBox获取每个项目的ItemContainer,查找{{1}},然后设置它的检查状态。