I'm trying to customize a ListView's GridViewColumnHeader on a column-by-column basis. I've been able to do this by manually setting each columns' GridViewColumnHeader as inline XAML (see the "Thing 2" column), which is OK but super repetitive, but I'd really rather have a reusable style with a control template with some attached properties (attempts are in the "Thing 1" column).
Basically, I need to style a unit of measurement text block, as well as a footer marker text block.
The attached properties appear to be set, but I haven't been able to figure out how to pull their values out in the template.
I realize that the GridColumnHeader isn't part of the visual tree, and that's likely the main hang-up here, but it seems so close!
The "Thing 1" column has the style set as inline XAML until I figure out how to get the attached property values. Ideally, it would be set in the control template like ExampleListViewHeader.
I've stripped out all the irrelevant code:
MainWindow.xaml
<Window.Resources>
<x:Array x:Key="ExampleItems" Type="{x:Type local:ExampleItems}">
<local:ExampleItems Cell1="Item 1-1" Cell2="Item 1-2" Cell3="Item 1-3" />
<local:ExampleItems Cell1="Item 2-1" Cell2="Item 2-2" Cell3="Item 2-3" />
<local:ExampleItems Cell1="Item 3-1" Cell2="Item 3-2" Cell3="Item 3-3" />
<local:ExampleItems Cell1="Item 4-1" Cell2="Item 4-2" Cell3="Item 4-3" />
</x:Array>
<Style x:Key="ExampleListView" TargetType="{x:Type ListView}">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="IsHitTestVisible" Value="False" />
<Setter Property="Margin" Value="0, 0, 0, 5" />
</Style>
<Style x:Key="ExampleListViewHeader" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
<TextBlock Text="{TemplateBinding Content}" Width="{TemplateBinding Width}" Padding="2, 0" TextWrapping="Wrap" VerticalAlignment="Bottom"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="FontFamily" Value="{DynamicResource PLC_Font}" />
<Setter Property="FontSize" Value="{DynamicResource PLC_FontSize_Sub_1}" />
<Setter Property="FontStyle" Value="Italic" />
<Setter Property="Foreground" Value="Black" />
</Style>
</Window.Resources>
<Grid>
<ListView ItemsSource="{StaticResource ExampleItems}" Style="{StaticResource ExampleListView}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Width="100"
local:HeaderAttachedProperties.Marker="1"
local:HeaderAttachedProperties.UofM=" (ft) "
DisplayMemberBinding="{Binding Cell1}">
<GridViewColumnHeader>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Thing 1" VerticalAlignment="Bottom"/>
<TextBlock Grid.Column="1" Text=" (ft) " FontSize="10" VerticalAlignment="Center"/>
<!--<TextBlock Grid.Column="2" Text="{TemplateBinding local:HeaderAttachedProperties.Marker}"/>-->
<!--<TextBlock Grid.Column="2" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:HeaderAttachedProperties.Marker)}"/>-->
<!--<TextBlock Grid.Column="2" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type GridViewColumn}}, Path=(local:HeaderAttachedProperties.Marker)}"/>-->
<!--<TextBlock Grid.Column="2" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=GridViewColumn}, Path=(local:HeaderAttachedProperties.Marker)}"/>-->
</Grid>
</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn Width="100"
DisplayMemberBinding="{Binding Cell2}">
<GridViewColumnHeader>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Thing 2" VerticalAlignment="Bottom"/>
<TextBlock Grid.Column="1" Text=" (ft) " FontSize="10" VerticalAlignment="Center"/>
<TextBlock Grid.Column="2" Text="*" FontSize="10" VerticalAlignment="Center"/>
</Grid>
</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn Header="Thing 3" DisplayMemberBinding="{Binding Cell3}" HeaderContainerStyle="{StaticResource ExampleListViewHeader}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
</Grid>
ExampleItems
public class ExampleItems
{
public string Cell1 { get; set; }
public string Cell2 { get; set; }
public string Cell3 { get; set; }
}
HeaderAttachedProperties
public class HeaderAttachedProperties : DependencyObject
{
public static readonly DependencyProperty MarkerProperty = DependencyProperty.RegisterAttached(
name: "Marker",
propertyType: typeof(string),
ownerType: typeof(HeaderAttachedProperties),
defaultMetadata: new PropertyMetadata(""));
public static string GetMarker(DependencyObject pDependencyObject)
{
return (string)pDependencyObject.GetValue(MarkerProperty);
}
public static void SetMarker(DependencyObject pDependencyObject, string pValue)
{
pDependencyObject.SetValue(MarkerProperty, pValue);
}
public static readonly DependencyProperty UofMProperty = DependencyProperty.RegisterAttached(
name: "UofM",
propertyType: typeof(string),
ownerType: typeof(HeaderAttachedProperties),
defaultMetadata: new PropertyMetadata(""));
public static string GetUofM(DependencyObject pDependencyObject)
{
return (string)pDependencyObject.GetValue(UofMProperty);
}
public static void SetUofM(DependencyObject pDependencyObject, string pValue)
{
pDependencyObject.SetValue(UofMProperty, pValue);
}
}
You do not necessarily need a
ControlTemplate. You can use aDataTemplateinstead. In order to bind the attached properties onGridViewColumn, you can use theColumnproperty ofGridViewColumnHeader.If you parameterize the first
TextBlock, too, you could extract and reuse it.You can of course change the
ControlTemplateinstead, but you should be careful, because the it defines the visual appearance and states of the control. In your current template, you lose most of the states.I omitted the
TextWrappingandVerticalAlignmentproperties, reintroduce them where intended.