Click here to Skip to main content
15,867,765 members
Articles / Desktop Programming / WPF

Silverlight Glass DataGrid Header Styles

Rate me:
Please Sign up or sign in to vote.
4.92/5 (27 votes)
14 Apr 2010CPOL8 min read 127K   5.6K   41   37
Silverlight glass style DataGrid header with glow animation on mouse-over.

Image1.gif

Introduction

This article takes you through steps to create glass style DataGrid-headers with mouse-over and pressed states, with an animated glow effect on mouse-over. This tutorial uses Visual Studio 2010 RC and Silverlight 4. This article explains how to:

  • Create a Silverlight project
  • Create a DataGrid and bind sample data
  • Apply style templates to a DataGrid
  • Create a glassy effect for the DataGrid header
  • Create VisualStateManagers for mouse-over and pressed states
  • Create a glow animation on the header on mouse-over
  • Change the style template for different DataGrid header colors

Creating a Basic DataGrid

This section takes you through creating a Silverlight application and a DataGrid. If you already have a Silverlight application and data bound to a DataGrid, you can skip to the "Creating a Grid Style" section.

Create a new Silverlight Application and call it GlassyGrid. In your MainPage.xaml, create a StackPanel and then drag and drop and DataGrid from the toolbar.

XML
<StackPanel HorizontalAlignment="Center" Margin="0,20,0,20" >
    <sdk:DataGrid Name="dataGrid1" Height="235" 
       Width="400" AutoGenerateColumns="True" 
       HorizontalAlignment="Center" />
</StackPanel>

Creating Sample Data for the Datagrid

Create a new class in your Silverlight Project called Data.cs. Now, add the following code to your Data class:

C#
public string Column1 { get; set; }
public string Column2 { get; set; }
public int Column3 { get; set; }
public bool Column4 { get; set; }

Open the MainPage.xaml.cs file and change your MainPage function to this:

C#
public MainPage()
{
    InitializeComponent();

    List<Data> source = new List<Data>();
    int itemsCount = 100;

    for (int i = 0; i < itemsCount; i++)
    {
        source.Add(new Data()
        {
            Column1 = "Data" + i,
            Column2 = "Second Column" + i,
            Column3 = i,
            Column4 = (i % 2 == 0)
        });
    }

    // Bind the datagrid
    dataGrid1.ItemsSource = source;
}

This creates some data and binds the data to the DataGrid. Run the application and you should see the basic DataGrid. The next section will take you through steps to create a style and apply it to the DataGrid.

Image 2

Creating a Style Resource Dictionary

To enhance the look and feel of the DataGrid, we create styles that can be applied to the DataGrid. Styles can generally be put into a ResourceDictionary file in your project. A ResourceDictionary provides a hash table/dictionary implementation that contains keyed WPF resources used by components in a WPF application, and can be used to store re-usable Styles for our DataGrid. To create a Style Resource Dictionary, right-click on your Application project and select Add -> New Folder. Name the folder Assets. Right-click on the Assets folder and Add -> New Item. Select "Silverlight Resource Dictionary" and change the "Name:" to Styles.xaml.

Image 3

You should now have the Styles.xaml file in your Solution:

Image 4

Include the newly created Styles.xaml in the Application.Resources tag in the App.xaml file:

XML
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
           <ResourceDictionary Source="Assets/Styles.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

Creating a Grid Style

Now create a style to modify the DataGrid's row colors and GridLines and a few other styles. Before you create a new style for the DataGrid, the following references need to be added in the ResourceDictionary tag:

XML
xmlns:local="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:localprimitives="clr-namespace:System.Windows.Controls.
                       Primitives;assembly=System.Windows.Controls.Data"

Add the following Style. This creates a new style called DataGridStyle targeted for the DataGrid.

XML
<Style x:Key="DataGridStyle"  TargetType="local:DataGrid">
    <Setter Property="RowBackground" Value="#FFFFFF" />
    <Setter Property="AlternatingRowBackground" Value="#EBEBED" />
    <Setter Property="RowHeight" Value="18" />        
    <Setter Property="GridLinesVisibility" Value="All"/>
    <Setter Property="HeadersVisibility" Value="Column" />
    <Setter Property="HorizontalGridLinesBrush" Value="#A0A0A0" />
    <Setter Property="HorizontalScrollBarVisibility" Value="Auto" />
    <Setter Property="VerticalScrollBarVisibility" Value="Auto" />
    <Setter Property="SelectionMode" Value="Single" />
    <Setter Property="CanUserReorderColumns" Value="False" />
    <Setter Property="CanUserResizeColumns" Value="False" />
    <Setter Property="CanUserSortColumns" Value="True" />
    <Setter Property="AutoGenerateColumns" Value="True" />
    <Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected" />
</Style>

Your Styles.xaml should look like this:

XML
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
    xmlns:localprimitives="clr-namespace:System.Windows.Controls.
                           Primitives;assembly=System.Windows.Controls.Data">

<Style x:Key="DataGridStyle"  TargetType="local:DataGrid">
    <Setter Property="RowBackground" Value="#FFFFFF" />
    <Setter Property="AlternatingRowBackground" Value="#EBEBED" />
    <Setter Property="RowHeight" Value="18" />        
    <Setter Property="GridLinesVisibility" Value="All"/>
    <Setter Property="HeadersVisibility" Value="Column" />
    <Setter Property="HorizontalGridLinesBrush" Value="#A0A0A0" />
    <Setter Property="HorizontalScrollBarVisibility" Value="Auto" />
    <Setter Property="VerticalScrollBarVisibility" Value="Auto" />
    <Setter Property="SelectionMode" Value="Single" />
    <Setter Property="CanUserReorderColumns" Value="False" />
    <Setter Property="CanUserResizeColumns" Value="False" />
    <Setter Property="CanUserSortColumns" Value="True" />
    <Setter Property="AutoGenerateColumns" Value="True" />
    <Setter Property="RowDetailsVisibilityMode" 
                    Value="VisibleWhenSelected" />
</Style>

Next, we need to tell the DataGrid in our MainPage.xaml to use this Style. Add Style="{StaticResource DataGridStyle}" to the DataGrid control:

XML
<sdk:DataGrid Name="dataGrid1" Height="235" Width="400" 
   AutoGenerateColumns="True" HorizontalAlignment="Center" 
   Style="{StaticResource DataGridStyle}" />

Run the application and you should see the DataGrid with alternating row colors and grid lines.

Image 5

Creating a Glass Effect Style Template for the DataGrid Header

This is where we will create a glass effect template for our DataGrid header and also add the three states: normal, mouse-over, and pressed, for the header. We'll create a new style as before, with a few properties like FontSize and Foreground. We also change the DataGrid to use the new header template style when rendering the column headers.

Styles.xaml
XML
<Style TargetType="localprimitives:DataGridColumnHeader" 
            x:Key="DataGridHeaderGlassEffect" >
    <Setter Property="FontSize" Value="11"/ >
    <Setter Property="Foreground" Value="#EEEEEE"/>
</Style>
MainPage.xaml
XML
<sdk:DataGrid Name="dataGrid1" Height="235" 
   Width="400" AutoGenerateColumns="True" 
   HorizontalAlignment="Center" Style="{StaticResource DataGridStyle}" 
    ColumnHeaderStyle="{StaticResource DataGridHeaderGlassEffect}" />

Next, we create a style template for the DataGrid header. Just after the Setter Property-Foreground, add the following code:

XML
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="localprimitives:DataGridColumnHeader">
        </ControlTemplate>
    </Setter.Value>
</Setter>

The ControlTemplate is used to customize the look and feel of the object in target - in our case, the DataGrid header. This is one of the most powerful features of WPF where you can create the desired user experience. In order to place the controls we are about to create, we first create a Grid object that will be a placeholder for our elements. Create the grid inside the ControlTemplate tags:

Styles.xaml
XML
<Grid Name="Root">
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
</Grid>

The Grid contains 3 columns and 3 rows, so we can place the header text and sorting icon and the column separator in positions. First, we create a Rectangle to display the header's background color. We use #FF679800 for a green color. This is placed inside the Grid tags and right after GridColumnDefinition.

XML
<Rectangle x:Name="BackgroundRectangle" Stretch="Fill" 
  Fill="#FF679800" Grid.ColumnSpan="2" Grid.RowSpan="2"  />

1. Creating the Header Text

To display the text for the header, we use a ContentPresenter and name it HeaderText. In order to set the properties of the ContentPresenter, we use {TemplateBinding}. TemplateBinding links the value of a property in a control template to be the value of some other exposed property on the templated control. This way, the ContentPresenter sets the data for the text, and also the cursor, alignment, and margin from the exposed properties of the grid itself.

XML
<ContentPresenter x:Name="HeaderText" Grid.RowSpan="2" 
    Content="{TemplateBinding Content}" Cursor="{TemplateBinding Cursor}" 
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
    Margin="{TemplateBinding Padding}" />

2. Creating the Column Separator

We create another Rectangle for the Column Separator. The color of the Separator comes from the SeparatorBrush property of the DataGrid. It takes the default color if the DataGrid does not have a value for SeparatorBrush. We also do not want to display the separator if the GridLinesVisibility property of the DataGrid is set to not show the grid lines.

XML
<Rectangle Name="VerticalSeparator" Grid.RowSpan="2" 
   Grid.Column="2" Width="1" VerticalAlignment="Stretch" 
   Fill="{TemplateBinding SeparatorBrush}" 
   Visibility="{TemplateBinding SeparatorVisibility}" />

3. Creating the Sort Icon

In order to create the sort icon, we use Path Markup Syntax [msdn:Path Markup Syntax]. Basically, we want to construct the sort icon using the path co-ordinates (-3,3) - (3,3) - (0,0) - (-3,3).

Image 6

Hence the Data for our sort icon would be "F1 M -3,3 L 3,3 L 0,0 Z". "F1" denotes that the fill rule is Nonzero, and the "Z" at the end indicates the end point should be joined to the start point.

XML
<Path Grid.RowSpan="2" Name="SortIcon" HorizontalAlignment="Left" 
        VerticalAlignment="Center" Opacity="0" 
        Grid.Column="1" Stretch="Uniform" Width="8" 
        Data="F1 M -3,3 L 3,3 L 0,0 Z ">
    <Path.Fill>
        <SolidColorBrush Color="#FFFFFFFF" />
    </Path.Fill> 
    <Path.RenderTransform>
        <TransformGroup>
            <ScaleTransform x:Name="SortIconTransform" />
        </TransformGroup>
    </Path.RenderTransform>
</Path>

We also added a ScaleTransform under RenderTransform that can be used to flip the image when sorted descending. We'll leave the Opacity of the object to "0" instead of "1" because we want to display the sort icon only when the column header is clicked. This will be controlled by the VisualStateManager, which we will discuss shortly.

4. Creating the Glass Effect

We've now created the basic header structure, with background, text, separator, and the sort icon. To create a glass effect, we create three layers. One called the 'shine' that creates that look of glass in normal state, one called 'glow' that creates a glow effect on mouse-over, and another called "dark" that creates a darker background in pressed state. We place these layers in Borders. We would place this between the BackgroundRectangle and the HeaderText.

XML
<Border BorderBrush="Transparent" BorderThickness="1,1,1,1" 
            Grid.ColumnSpan="3" Grid.RowSpan="3">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.5*"/>
            <RowDefinition Height="0.5*"/>
        </Grid.RowDefinitions>
        <!--dark-->
            <Border HorizontalAlignment="Stretch" Margin="0,0,0,0" 
               x:Name="dark" Width="Auto" 
               Grid.ColumnSpan="3" Grid.RowSpan="3" 
                    Background="#66000000" Opacity="0"/>
         <!--glow -->
        <Border Opacity="0" HorizontalAlignment="Stretch" 
               x:Name="glow" Width="Auto" 
               Grid.RowSpan="2" Grid.ColumnSpan="3">
            <Border.Background>
                <RadialGradientBrush> 
                    <RadialGradientBrush.RelativeTransform>
                        <TransformGroup>
                            <ScaleTransform ScaleX="1.7" ScaleY="2.2"/>
                            <SkewTransform AngleX="0" AngleY="0"/>
                            <RotateTransform Angle="0"/>
                            <TranslateTransform X="-0.3" Y="-0.1"/>
                        </TransformGroup>
                    </RadialGradientBrush.RelativeTransform>                  
                    <GradientStop Color="#B2FFFFFF" Offset="0"/>
                    <GradientStop Color="#00FFFFFF" Offset="1"/>
                </RadialGradientBrush>
            </Border.Background>
        </Border>
         <!--shine -->
        <Border HorizontalAlignment="Stretch" Margin="0,0,0,0" 
                x:Name="shine" Width="Auto" Grid.ColumnSpan="3">
            <Border.Background>
                <LinearGradientBrush EndPoint="0.5,0.9" StartPoint="0.5,0.1">
                    <GradientStop Color="#99FFFFFF" Offset="0"/>
                    <GradientStop Color="#33FFFFFF" Offset="1"/>
                </LinearGradientBrush>
            </Border.Background>
        </Border>
    </Grid>
</Border>

Run the application and you should see the DataGrid with the glassy headers.

Image 7

Adding Visual states

Note that the grid looks the same even on the mouse-over and pressed states. And the sort icon does not show when the header is sorted. We are going to fix that now. We would have to use the VisualStateManager for our purpose. The VisualStateManager enables you to specify states for a control, the appearance of a control when it is in a certain state, and when a control changes states. Include the following references in the ResourceDictionary:

XML
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"

1. Sort Icon States

We have three states for the sort icon - 'Unsorted', 'SortAscending', and 'SortDescending'. Create a <vsm:VisualStateManager.VisualStateGroups> between the <Grid Name="Root"> tag and add the three sorting states.

XML
<vsm:VisualStateManager.VisualStateGroups>
    <vsm:VisualStateGroup x:Name="SortStates" >
        <vsm:VisualStateGroup.Transitions>
            <vsm:VisualTransition GeneratedDuration="00:00:0.1" />
        </vsm:VisualStateGroup.Transitions>
        <vsm:VisualState x:Name="Unsorted" />
        <vsm:VisualState x:Name="SortAscending">
            <Storyboard>
                <DoubleAnimation Storyboard.TargetName="SortIcon" 
                    Storyboard.TargetProperty="Opacity" 
                    Duration="0" To="1.0" />
            </Storyboard>
        </vsm:VisualState>
        <vsm:VisualState x:Name="SortDescending">
            <Storyboard>
                <DoubleAnimation Storyboard.TargetName="SortIcon" 
                    Storyboard.TargetProperty="Opacity" 
                    Duration="0" To="1.0" />
                <DoubleAnimation Storyboard.TargetName="SortIconTransform" 
                    Storyboard.TargetProperty="ScaleY" 
                    Duration="0" To="-1" />
            </Storyboard>
        </vsm:VisualState>
    </vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>

In order to display the sort icon in the sorted state, we need to change the Opacity of the "SortIcon" layer from 0 to 1. This is accomplished by using a DoubleAnimation [mdsn:DoubleAnimation]. DoubleAnimation animates the value of a property between two target values using linear interpolation over a specified duration. TargetName specifies which control has to be affected by the animation, and TargetProperty specifies the property of the control that gets affected. In our case here, TargetName is set to the "SortIcon" control, and TargetProperty is set to "Opacity". We change the value of Opacity from 0 to 1. We need the animation to take effect immediately, so we set the Duration property to 0.

So on SortAscending, we change the Opacity of the "SortIcon" from 0 to 1 so that the icon becomes visible, and on SortDescending we also change the ScaleY from 1 to -1, thereby inverting the sort icon.

2. Mouse-over and Pressed States

Next, add the Visual states for the normal, mouse-over, and pressed states:

XML
<vsm:VisualStateGroup x:Name="CommonStates">
    <vsm:VisualState x:Name="Normal"/>
    <vsm:VisualState x:Name="MouseOver">
        <Storyboard>
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
                     Storyboard.TargetName="glow" 
                     Storyboard.TargetProperty="(UIElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00.4000000" Value="1"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </vsm:VisualState>
    <vsm:VisualState x:Name="Pressed">
        <Storyboard>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="shine" 
                       Storyboard.TargetProperty="Opacity">
                <SplineDoubleKeyFrame KeyTime="0" Value="0"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
                         Storyboard.TargetName="dark" 
                         Storyboard.TargetProperty="(UIElement.Opacity)">
                    <SplineDoubleKeyFrame KeyTime="00:00:00.0000000" Value="1"/>
                </DoubleAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" 
                    Duration="00:00:00.0010000" Storyboard.TargetName="glow" 
                    Storyboard.TargetProperty="(UIElement.Visibility)">
                <DiscreteObjectKeyFrame KeyTime="00:00:00">
                    <DiscreteObjectKeyFrame.Value>
                        <Visibility>Collapsed</Visibility>
                    </DiscreteObjectKeyFrame.Value>
                </DiscreteObjectKeyFrame>
            </ObjectAnimationUsingKeyFrames>
        </Storyboard>
    </vsm:VisualState>
</vsm:VisualStateGroup>

On MouseOver, we create an animated fade-in glow effect by changing the Opacity of the "glow" layer from 0 to 1 over a period of 4 seconds. This is accomplished by using Spline key frames, such as SplineDoubleKeyFrame in a DoubleAnimationUsingKeyFrames segment [mdsn:DoubleAnimationUsingKeyFrames]. The DoubleAnimationUsingKeyFrames animates the value of a property along a set of KeyFrames. The SplineDoubleKeyFrame creates a variable transition between values. The KeyTime specifies the precise timing when a particular key frame should take place- 4 seconds in our case ("00:00:00.4000000"). Again, Storyboard.TargetName is set to the "glow" control and Storyboard.TargetProperty is set to the "Opactity" of the "glow" control.

On Pressed state, we hide both the "glow" and the "shine" layer and display the "dark" layer. The "BackgroundRectangle" object shows through the "dark" layer in the pressed state.

...and Voila!

Run the application and you should have the following states for the DataGrid header:

Image 8Image 9

Here is the complete Styles.xaml file:

XML
<ResourceDictionary    
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:System.Windows.Controls;
                 assembly=System.Windows.Controls.Data"
    xmlns:localprimitives="clr-namespace:System.Windows.Controls.
                           Primitives;assembly=System.Windows.Controls.Data"
    xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">

    <Style x:Key="DataGridStyle"  TargetType="local:DataGrid">
        <Setter Property="RowBackground" Value="#FFFFFF" />
        <Setter Property="AlternatingRowBackground" Value="#EBEBED" />
        <Setter Property="RowHeight" Value="18" />
        <Setter Property="GridLinesVisibility" Value="All"/>
        <Setter Property="HeadersVisibility" Value="Column" />
        <Setter Property="HorizontalGridLinesBrush" Value="#A0A0A0" />
        <Setter Property="HorizontalScrollBarVisibility" Value="Auto" />
        <Setter Property="VerticalScrollBarVisibility" Value="Auto" />
        <Setter Property="SelectionMode" Value="Single" />
        <Setter Property="CanUserReorderColumns" Value="False" />
        <Setter Property="CanUserResizeColumns" Value="False" />
        <Setter Property="CanUserSortColumns" Value="True" />
        <Setter Property="AutoGenerateColumns" Value="True" />
        <Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected" />
    </Style >

    <Style TargetType="localprimitives:DataGridColumnHeader" 
                   x:Key="DataGridHeaderGlassEffect" >
        <Setter Property="FontSize" Value="11"/>
        <Setter Property="Foreground" Value="#EEEEEE"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="localprimitives:DataGridColumnHeader">
                    <Grid Name="Root">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*" />
                            <RowDefinition Height="*" />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>

                        <Rectangle x:Name="BackgroundRectangle" Stretch="Fill" 
                            Fill="#FF679800" Grid.ColumnSpan="2" 
                            Grid.RowSpan="2"  />
                        <Border BorderBrush="Transparent" 
                                BorderThickness="1,1,1,1" 
                                Grid.ColumnSpan="3" Grid.RowSpan="3">
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="0.5*"/>
                                    <RowDefinition Height="0.5*"/>
                                </Grid.RowDefinitions>
                                <!--dark-->
                                <Border HorizontalAlignment="Stretch" 
                                   Margin="0,0,0,0" x:Name="dark" 
                                   Width="Auto" Grid.ColumnSpan="3" 
                                   Grid.RowSpan="3" 
                                   Background="#66000000" 
                                   Opacity="0"/>
                                <!--glow-->
                                <Border Opacity="0"
                                 HorizontalAlignment="Stretch" x:Name="glow" 
                                 Width="Auto" Grid.RowSpan="2" 
                                 Grid.ColumnSpan="3">
                                    <Border.Background>
                                        <RadialGradientBrush>
                                            <RadialGradientBrush.RelativeTransform>
                                                <TransformGroup>
                                                    <ScaleTransform ScaleX="1.7" 
                                                       ScaleY="2.2"/>
                                                    <SkewTransform AngleX="0" 
                                                       AngleY="0"/>
                                                    <RotateTransform Angle="0"/>
                                                    <TranslateTransform X="-0.3" 
                                                       Y="-0.1"/>
                                                </TransformGroup>
                                            </RadialGradientBrush.RelativeTransform>
                                            <GradientStop Color="#B2FFFFFF" 
                                               Offset="0"/>
                                            <GradientStop Color="#00FFFFFF" 
                                               Offset="1"/>
                                        </RadialGradientBrush>
                                    </Border.Background>
                                </Border>
                                <!--shine-->
                                <Border HorizontalAlignment="Stretch" 
                                         Margin="0,0,0,0" x:Name="shine" 
                                         Width="Auto" 
                                         Grid.ColumnSpan="3">
                                    <Border.Background>
                                        <LinearGradientBrush EndPoint="0.5,0.9" 
                                                StartPoint="0.5,0.1">
                                            <GradientStop Color="#99FFFFFF" 
                                                Offset="0"/>
                                            <GradientStop Color="#33FFFFFF" 
                                                Offset="1"/>
                                        </LinearGradientBrush>
                                    </Border.Background>
                                </Border>
                            </Grid>
                        </Border>
                        <ContentPresenter x:Name="HeaderText" 
                          Grid.RowSpan="2" 
                          Content="{TemplateBinding Content}" 
                          Cursor="{TemplateBinding Cursor}" 
                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
                          Margin="{TemplateBinding Padding}" />
                        <Rectangle Name="VerticalSeparator" 
                           Grid.RowSpan="2" Grid.Column="2" 
                           Width="1" VerticalAlignment="Stretch" 
                           Fill="{TemplateBinding SeparatorBrush}" 
                           Visibility="{TemplateBinding SeparatorVisibility}" />
                        <Path Grid.RowSpan="2" Name="SortIcon" 
                          RenderTransformOrigin=".5,.5" 
                          HorizontalAlignment="Left" 
                          VerticalAlignment="Center" Opacity="0" 
                          Grid.Column="1" Stretch="Uniform" 
                          Width="8" Data="F1 M -3,3 L 3,3 L 0,0 Z ">
                            <Path.Fill>
                                <SolidColorBrush Color="#FFFFFFFF" />
                            </Path.Fill>
                            <Path.RenderTransform>
                                <TransformGroup>
                                    <ScaleTransform x:Name="SortIconTransform"  />
                                </TransformGroup>
                            </Path.RenderTransform>
                        </Path>
                        <vsm:VisualStateManager.VisualStateGroups>
                            <vsm:VisualStateGroup x:Name="SortStates" >
                                <vsm:VisualStateGroup.Transitions>
                                    <vsm:VisualTransition GeneratedDuration="00:00:0.1" />
                                </vsm:VisualStateGroup.Transitions>
                                <vsm:VisualState x:Name="Unsorted" />
                                <vsm:VisualState x:Name="SortAscending">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="SortIcon" 
                                           Storyboard.TargetProperty="Opacity" 
                                           Duration="0" To="1.0" />
                                    </Storyboard>
                                </vsm:VisualState>
                                <vsm:VisualState x:Name="SortDescending">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="SortIcon" 
                                          Storyboard.TargetProperty="Opacity" 
                                          Duration="0" To="1.0" />
                                        <DoubleAnimation 
                                          Storyboard.TargetName="SortIconTransform" 
                                          Storyboard.TargetProperty="ScaleY" 
                                          Duration="0" To="-1" />
                                    </Storyboard>
                                </vsm:VisualState>
                            </vsm:VisualStateGroup>
                            <vsm:VisualStateGroup x:Name="CommonStates">
                                <vsm:VisualState x:Name="Normal"/>
                                <vsm:VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <DoubleAnimationUsingKeyFrames 
                                          BeginTime="00:00:00" 
                                          Storyboard.TargetName="glow" 
                                          Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame
                                               KeyTime="00:00:00.4000000" Value="1"/>
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </vsm:VisualState>
                                <vsm:VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <DoubleAnimationUsingKeyFrames 
                                              Storyboard.TargetName="shine" 
                                              Storyboard.TargetProperty="Opacity">
                                          <SplineDoubleKeyFrame KeyTime="0" Value="0"/>
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
                                          Storyboard.TargetName="dark" 
                                          Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame 
                                              KeyTime="00:00:00.0000000" Value="1"/>
                                        </DoubleAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" 
                                               Duration="00:00:00.0010000" 
                                               Storyboard.TargetName="glow" 
                                               Storyboard.TargetProperty=
                                                  "(UIElement.Visibility)">
                                            <DiscreteObjectKeyFrame KeyTime="00:00:00">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Collapsed</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </vsm:VisualState>
                            </vsm:VisualStateGroup>
                        </vsm:VisualStateManager.VisualStateGroups>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Changing header colors

The basic color theme of the DataGrid header is set by the Rectangle object "BackgroundRectangle". To create a DataGrid header with any other color, all you have to do is change the Fill property of the "BackgroundRectangle" Rectangle object to any other color. Everything else, including the animated glow and the sorting, will work the same. You can also modify the look and feel of the DataGrid header by modifying the style template to, for example, create rounded borders for the grid headers and so on. The downloadable source code contains these examples.

Image 10

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionFor Text wrapping Pin
SoTAmARTin14-May-15 18:30
SoTAmARTin14-May-15 18:30 
QuestionGridHeaderPresenter alignments using Setter Pin
Damo777_1439-Jun-14 11:58
Damo777_1439-Jun-14 11:58 
GeneralMy vote of 5 Pin
Amandeep heer24-Apr-13 1:13
Amandeep heer24-Apr-13 1:13 
QuestionText Wrapping Pin
Member 869046223-Apr-13 2:22
Member 869046223-Apr-13 2:22 
QuestionAlmost a great solution Pin
CwFord20-Dec-12 14:30
CwFord20-Dec-12 14:30 
QuestionGrid Headers Pin
Candice Blash28-Aug-12 9:08
Candice Blash28-Aug-12 9:08 
AnswerRe: Grid Headers Pin
Tingu Abraham28-Aug-12 11:31
Tingu Abraham28-Aug-12 11:31 
GeneralRe: Grid Headers Pin
Candice Blash29-Aug-12 2:37
Candice Blash29-Aug-12 2:37 
GeneralVery helpful code Pin
Ocrammai27-Jul-12 2:43
professionalOcrammai27-Jul-12 2:43 
Thank you sooo much


One of the most helpful articles in a long time for me.
Well thought of, very impressive.

Thaks a mill Big Grin | :-D Big Grin | :-D Big Grin | :-D
QuestionUsing In WPF Pin
Firpas3-May-12 1:49
Firpas3-May-12 1:49 
QuestionOther uses Pin
RTS@WORK20-Mar-12 4:08
RTS@WORK20-Mar-12 4:08 
AnswerRe: Other uses Pin
Tingu Abraham20-Mar-12 6:18
Tingu Abraham20-Mar-12 6:18 
Questionuse this with windows forms? Pin
Roko Mise3-Mar-12 1:43
Roko Mise3-Mar-12 1:43 
AnswerRe: use this with windows forms? Pin
Tingu Abraham6-Mar-12 4:21
Tingu Abraham6-Mar-12 4:21 
QuestionHow to make column header center? Pin
codemaster_ghaul2-Aug-11 17:27
codemaster_ghaul2-Aug-11 17:27 
AnswerRe: How to make column header center? Pin
adrian lewis8-Apr-13 0:22
adrian lewis8-Apr-13 0:22 
GeneralRe: How to make column header center? Pin
lucasgcaro15-Aug-15 13:32
lucasgcaro15-Aug-15 13:32 
GeneralSilverlight datagrid populate new row Pin
Anjanaa31-May-11 11:12
Anjanaa31-May-11 11:12 
GeneralGrid ToolTip Pin
Yogesh Potdar22-Feb-11 18:44
Yogesh Potdar22-Feb-11 18:44 
GeneralRe: Grid ToolTip Pin
Tingu Abraham16-Mar-11 11:21
Tingu Abraham16-Mar-11 11:21 
GeneralResize Columns Pin
covard10-Dec-10 12:35
covard10-Dec-10 12:35 
GeneralRe: Resize Columns Pin
Tingu Abraham16-Mar-11 11:40
Tingu Abraham16-Mar-11 11:40 
GeneralRe: Resize Columns Pin
Henry Chien10-Oct-11 18:23
Henry Chien10-Oct-11 18:23 
GeneralHelp Pin
diego mesa tabares2-Jul-10 13:26
diego mesa tabares2-Jul-10 13:26 
GeneralRe: Help Pin
Tingu Abraham13-Jul-10 12:58
Tingu Abraham13-Jul-10 12:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.