Using the Silverlight Toolkit LayoutTransformer Control for Angled Column Header Text

I recently inherited the DataGrid control and, after reading over customer feedback and forum posts, one of the tasks I gave myself was to create a code example for the DataGrid.ColumnHeaderStyle property. After poking around I thought it would be interesting, and hopefully useful, to show how to angle the content of column headers using the ColumnHeaderStyle property. This would save screen real estate since headers, which by default are property names, can be lengthy, and the displayed values are often short. I mucked around and came up with the following:

<UserControl

xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data"

>

<my:DataGrid.ColumnHeaderStyle>
<Style TargetType="primitives:DataGridColumnHeader" >
<Setter Property="FontSize" Value="10" />
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate >
<TextBlock Text="{Binding}" >
<TextBlock.RenderTransform>
<RotateTransform Angle="-35" />
</TextBlock.RenderTransform>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</my:DataGrid.ColumnHeaderStyle>

 

Here’s the column headers when I ran the code. (In this example, for simplicity, I’ve bound the DataGrid to the Children property of LayoutRoot)

image

Unfortunately, the tops of the headers were cut off and I couldn’t figure out why. I consulted my friend Margaret, who used to own the Silverlight layout docs and the WPF Datagrid docs up until recently, and she pointed out that the transform is done after the measure and layout pass so the layout slot allowed for the content reflects the pre-transformed data.

(As a side note, our conversation resulted in her posting about this problem on the WPF UE team blog. You can check out here.)

Here’s the info about how rotated elements are clipped from the Silverlight Layout System topic:

The following illustration shows a child element that is rotated and now extends beyond its assigned layout slot.

Layout Clip

In this case, the layout system clips the child element and displays only the portion of the element that fits inside the layout slot.

Now I understood why my headers where being cut off, but I didn’t know how to fix it. As a result, I did some searching and I ended up at David Anson’s blog. He created a control for Silverlight that operates in much the same way that the LayoutTransform control does in WPF. The WPF LayoutTransform control performs the transform before the measure and layout passes so the correct layout slot is allocated for the control content.

It turns out that since David wrote this post, his control, now named the LayoutTransformer, has been added to the Silverlight Toolkit. I already had the Toolkit installed, so it was just a matter of referencing the correct assembly, which is the System.Windows.Control.Layout.Toolkit assembly, adding the XAML namespace mapping, and adding the control to my XAML. Here’s my new code:

 

 

<UserControl

xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data"
xmlns:layout="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"

>

<my:DataGrid.ColumnHeaderStyle>
<Style TargetType="primitives:DataGridColumnHeader" >
<Setter Property="FontSize" Value="10" />
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate >
<layout:LayoutTransformer>
<layout:LayoutTransformer.LayoutTransform>
<RotateTransform Angle="-35"/>
</layout:LayoutTransformer.LayoutTransform>
<TextBlock Text="{Binding}" />
</layout:LayoutTransformer>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</my:DataGrid.ColumnHeaderStyle>

Here’s what my revised code looks like when I run it:

image 

Angled content, and it’s all on the screen. Woo Hoo!

--Cheryl