Editing Default ColumnHeaderStyle

Dec 2, 2008 at 3:30 PM
I need to extract the default ColumnHeaderStyle for the DataGrid in order to make a minor cosmetic change.  I was able to do this for a standard GridViewColumnHeader using Expression Blend, but when I try editing the style for a column header in a DataGrid I only have the option to create a new style rather than edit the existing one.

I want the overall style and behaviour to remain the same as the default, the only thing I want to change is the colour of the header border for a selected column (or when a mouseover occurs on the column header).  Microsoft seem to like setting the default colour to orange, which doesn't fit in with the rest of our application style.

Has anyone managed to extract the default style?   I know I can create a new one from scratch, but for such  a minor change that seems a little drastic.

Thanks in advance
Dec 2, 2008 at 3:49 PM
Hi,

A few techniques, extract the control template at runtime:

http://learnwpf.com/Posts/Post.aspx?postId=a3e4319b-b790-40b6-b92a-4b9b0b9d65b9

Use Reflector to decompile the BAML (birnary XAML) from the assembly:

http://wpfwonderland.wordpress.com/2007/01/23/latest-version-of-reflector-can-dissemble-baml-to-xaml/

Or, just download the WPF Toolkit sources and open up the Generic.xaml directly. Here you go:

  <Style x:Key="ColumnHeaderGripperStyle" TargetType="{x:Type Thumb}">
    <Setter Property="Width" Value="8"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Cursor" Value="SizeWE"/>
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type Thumb}">
          <Border Padding="{TemplateBinding Padding}"
                    Background="{TemplateBinding Background}"/>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>


  <Style x:Key="{x:Type dgp:DataGridColumnHeader}" TargetType="{x:Type dgp:DataGridColumnHeader}">
    <Setter Property="VerticalContentAlignment" Value="Center" />
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type dgp:DataGridColumnHeader}">
          <Grid>
            <dg:DataGridHeaderBorder SortDirection="{TemplateBinding SortDirection}"
                                     IsHovered="{TemplateBinding IsMouseOver}"
                                     IsPressed="{TemplateBinding IsPressed}"
                                     IsClickable="{TemplateBinding CanUserSort}"
                                     Background="{TemplateBinding Background}"
                                     BorderBrush="{TemplateBinding BorderBrush}"
                                     BorderThickness="{TemplateBinding BorderThickness}"
                                     Padding ="{TemplateBinding Padding}"
                                     SeparatorVisibility="{TemplateBinding SeparatorVisibility}"
                                     SeparatorBrush="{TemplateBinding SeparatorBrush}">
                <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
            </dg:DataGridHeaderBorder>

            <Thumb x:Name="PART_LeftHeaderGripper"
                   HorizontalAlignment="Left"
                   Style="{StaticResource ColumnHeaderGripperStyle}"/>
            <Thumb x:Name="PART_RightHeaderGripper"
                   HorizontalAlignment="Right"
                   Style="{StaticResource ColumnHeaderGripperStyle}"/>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>

Regards,
Colin E.
--
http://wpfadventures.wordpress.com/ - my WPF blog
http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx - WPF DataGrid Practical Examples



Dec 2, 2008 at 3:53 PM
Thanks Colin, I can't believe I completely missed Generic.xaml, I must be blind, I had the solution open right in front of me! 

Thanks again, would probably have taken me ages to spot that!
Dec 2, 2008 at 4:03 PM
Doh!  It seems that the part of the style that I want to override must be inherited from the base control as it isn't defined in Generic.xaml

I think it's time to try extracting it at runtime or using Reflector, hopefully I'll be able to find what I need that way.
Dec 3, 2008 at 3:22 PM
Edited Dec 3, 2008 at 3:26 PM
I extracted the control template at runtime, hoping that the ColumnHeaderStyle might be included, but it wasn't, just got the same template defined in Generic.xaml (probably rather predictable really!)

I thought I might be able to extract the ColumnHeaderStyle in the same way by using the code provided in Colin's first link...

StringBuilder sb = new StringBuilder();
using (TextWriter writer = new StringWriter(sb))
{
    System.Windows.Markup.XamlWriter.Save(MyDataGrid.ColumnHeaderStyle, writer);
}


However, the ColumnHeaderStyle seemed to be null, which is puzzling.  I know I haven't specifically assigned a style, but there is obviously some default styling being applied and I can't find a way to extract it.

I need to retain the general style of the control as I need to keep the little triangle/arrow that is displayed when a column is sorted, all I want to change is the bottom border on the column headers - it turns orange when a mouseover or click event occurs on the column header, whereas I want to be able to use a brush defined in my resource dictionary as the orange just doesn't look right on our application.

Has anyone got any other ideas as to how I can extract this style information?

Thanks
Coordinator
Dec 3, 2008 at 6:48 PM
Hi,

You will not find the xaml which for those effects of DataGridColumnHeader and DataGridRowHeader in generic.xaml. The core logic for these controls is implemented in code (for perf reasons similar to that of ButtonChrome) as DataGridHeaderBorder class. If you look at this class you will find all the rendering logic which does this.

The options are....

  1. Take the code from DataGridHeaderBorder and create your own class with appropriate modifications and use it instead.
  2. Or retemplate DataGridColumnHeader from the scratch (without using DataGridHeaderBorder)
Dec 4, 2008 at 9:42 AM
Thanks VamseeP, you may have just saved the day!

I assumed that the styling would have been done in the same way as the standard GridViewColumnHeader, but obviously not!  I think I'll try modifying the code for the DataGridHeaderBorder, it should be as simple as adding a new dependency property to bind the border colour to.
Dec 4, 2008 at 12:19 PM
Edited Dec 4, 2008 at 12:20 PM
Hi Tabby,

Personally - I would go for the second option. Adding the sort glyphs to your control template is not that tricky:

http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx#header

Regards,
Colin E.
--
http://wpfadventures.wordpress.com/ - my WPF blog
http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx - WPF DataGrid Practical Examples


Dec 5, 2008 at 10:33 AM
Thanks Colin, 

After looking at the DataGrid a bit more it seems that it doesn't quite have what we need for our application - we need to be able to bind a RoutedCommand to the grid, so that the command is executed when a row is double-clicked.  We had previously customised the ListView control to allow the binding of commands, but have realised that we need more features and are looking at third-party controls rather than having to do all of the work ourselves.  I'm currently looking at the DevExpress GridControl for WPF, but I'm not entirely sure that's got everything we need either. 
Dec 5, 2008 at 11:20 AM
Hi Tabby,

By some coincidence Marlon Grech has just posted an article on his blog about binging commands to event via attached properties. I have not had a chance to look at it in detail yet, but from a brief read it looks very simple and neat. It might be just what you are looking for:

http://marlongrech.wordpress.com/2008/12/04/attachedcommandbehavior-aka-acb/

Regards,
Colin E.
--
http://wpfadventures.wordpress.com/ - my WPF blog
http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx - WPF DataGrid Practical Examples