DataTrigger in binding CellTemplate to HeaderTemplate; can it work?

The goal here is to check all grid flags if the header flag changes:

<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> 

It looks like:

Screen

For some reason, the trigger does not fire.

Any ideas?

+2
source share
2 answers

ElementName binding inside a DataTemplate cannot reach an element outside the template, as you noticed. This is due to the fact that it can be created several times and has its own pointer, so any ElementName binding that you create inside the DataTemplate will look inside the template for another element with this name.

Looking at it with Snoop, we also see that the RelativeSource binding cannot be used directly, since they are in different parts of the visual tree

enter image description here

The only thing I can think of to get around this is to bind both CheckBox to a common ancestor, for example. parent DataGrid and use the attached property or the Tag property. Example

 <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> 

and

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

I don’t think that a normal DataBinding for a HeaderCheckBox is possible, because the CheckBox exists as part of the Template and it is in a different VisualTree branch than the DataGridItems

I usually do it the other way around: when the CheckBox header is checked, check the entire CheckBoxes line. My main reason for this is because CheckBoxes are usually there, so users can check / uncheck them, and if they are related to the status of the CheckBox header, the user cannot change them.

To implement this, I usually connect to the Click or Checked event in the CheckBox header.

If the state of the CheckBox.IsChecked line is tied to something in the ViewModel, I will connect this event to Command in my ViewModel and set the data item to which CheckBox.IsChecked bound to true / false depending on the state of the CheckBox header (usually passed as CommandParameter )

If the status of CheckBox.IsChecked not tied to anything, you can use the usual code to scroll through your DataGrid.Items , use ItemContainerGenerator to get the ItemContainer for each item, find the CheckBox and then set its check state.

0
source

Source: https://habr.com/ru/post/911891/


All Articles