WPF Toolkit DataGrid, Part II – Custom styling

This post is part of the WPF Toolkit DataGrid series. Here is a list with the complete set of blog posts:

Introduction

In Part I we went through basic DataGrid setup creating a sample application that showcased the usage of DataGridColumns. In this part we will dive into more advanced concepts. It is my ambition that you get a good understanding of how to setup a DataGrid to do whatever you wish without restrictions. In this part we will focus on restyling the DataGrid, DataGridColumnHeaders and DataGridRowHeaders.

Roadmap

  1. Visual breakdown of styles and layout
  2. Styling the DataGrid
  3. Styling DataGridColumnHeaders
  4. Styling DataGridRowHeaders
  5. Creating a new template for the SelectAllButton

Download sample source code

Here you can find the source code for this article.

Visual breakdown of layout and styles

Before we start digging dipper into DataGrid’s functionalities and restyling let’s take a look on what WPF Toolkit uses to build it. It is essential that you understand what each class is responsible for in order to find which styles you need to replace so that you can change the looks of a specific region of the DataGrid.

First let’s look at the DataGrid from a layout perspective. Along with the DataGrid this are the main components used to display the information inside of it:

These classes are the ones used by the DataGrid to render itself. They are the objects that end up on the application’s visual tree:

  • DataGridColumnHeadersPresenter: this control will go through the DataGridColumns collection of the DataGrid and create a DataGridColumnHeader for each;
  • DataGridColumnHeader: picks up the information in its DataGridColumn and renders it as a header on the corresponding column position;
  • DataGridRowsPresenter: the ItemsControl that iterates the ItemsSource creating a DataGridRow for each item;
  • DataGridRow: represents an item of ItemsSource;
  • DataGridRowHeader: this is a Button that lays on the beginning of each DataGridRow. It allows the user to select the row, resize it, and can be used to show information – for instance, on the current operation being performed over the selected row or still to provide error information;
  • DataGridCellsPresenter: this is the ItemsControl used to render each cell, based on the column bindings, for the DataGridRow bounded item;
  • DataGridCell: this is the control used to render a specific value of an Item. Essentially it is made of two templates, one to display the item and one for editing it;
  • DataGridDetailsPresenter: this is an extension of the DataGridRow used to show further information about a row than the one displayed by the cells. It is a panel that is normally laid bellow the cells. On WPF Toolkit’s DataGrid, by default, this panel is only shown when the user selects a row.

On the following image you can see where each of this controls are laid. Take some time to get to know what component is responsible for what part of the DataGrid.

Starting from the top, in the DataGrid, we will have a DataGridColumnHeadersPresenter used to present all DataGridColumnHeaders, there will be one header per bounded column. Each column header has two grippers. Inside the DataGrid along with the DataGridColumnHeadersPresenter there will be a DataGridRowsPresenter which will contain all our rows. The DataGridRow will contain a DataGridRowHeader and a DataGridCellsPresenter which contains all the DataGridCells. Also part of the DataGridRow, although not shown in the screenshot, is the DataGridDetailsPresenter, which can be used to present further details on the selected row.

If you use Snoop to browse the visual tree of our sample from Part I you will see the following (I have marked in red the items you should pay more attention to):

Side note: Snoop is a great tool for analyzing how a WPF application is structured. If you do not have this tool on you arsenal, stop reading, go to their web site, download it and install it. This is a must have if you are developing WPF applications.

You can see each of the classes we looked at above in the visual tree of our WPF sample application. Take some time to assimilate the structure used before proceeding.

By now you should have a solid understanding about the structure of the DataGrid. You should be able to easily spot each component along with which class is responsible for rendering it. This is the foundation for our next job – restyling the WPF Toolkit’s DataGrid.

Styling the DataGrid

Since the DataGrid is divided in several parts and each has individual styles, our ControlTemplate for it will not change that much, most of it will be based on the one that comes with WPF Toolkit.

The DataGrid style has five major components:

  • Select all button: this is the button on the top left corner of the DataGrid that is used to select all rows;
  • PART_ColumnHeadersPresenter: this is the ItemsControl used to present all of our DataGridColumnHeaders;
  • PART_ScrollContentPresenter: the main area of the DataGrid where all the DataGridRows will be rendered;
  • PART_VerticalScrollBar: renders the vertical scroll bar of our ScrollViewer;
  • PART_HorizontalScrollBar: renders the horizontal scroll bar of our ScrollViewer.

I have taken a screenshot from Snoop in order to show you how these parts fit together on visual tree:

In the last sample we worked with on Part I, you may have notice that the vertical scroll bar does not occupy the full height of the DataGrid. In our new style, we will make it fill that empty space. This is just a minor tweak in the default DataGrid ControlTemplate.

Since you may want to reuse this new style just add a new resource dictionary to your solution where you can place the new DataGrid style – in the sample code I have named it ‘DataGrid.Generic.xaml’ and placed it under the Themes folder.

The change we are planning to make is a small one, so we can reuse the style defined within WPF Toolkit, you just have to copy the DataGrid style from the ‘Generic.xaml’ file on WPF Toolkit and add it to your new dictionary. Find the definition of the vertical scroll bar in the ControlTemplate part of the style. Change Grid.Row to 0 and give it a Grid.RowSpan of 2, as shown below:

(…)
<ScrollBar Name="PART_VerticalScrollBar"
           Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" Orientation="Vertical"
           Maximum="{TemplateBinding ScrollableHeight}"
           ViewportSize="{TemplateBinding ViewportHeight}"
           Value="{Binding Path=VerticalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
           Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
(…)

Along with extending the scroll bar you can also style your DataGrid by setting some nice colors. To give your DataGrid a cooler look you can start by creating a series of brushes:

<!-- Generic brushes -->
<SolidColorBrush x:Key="DefaultControlBorderBrush" Color="#FF688CAF"/>
<SolidColorBrush x:Key="DefaultControlBackgroundBrush" Color="#FFE3F1FE"/>
<SolidColorBrush x:Key="DefaultControlForegroundBrush" Color="#FF10257F"/>

<!-- DataGrid related brushes -->
<SolidColorBrush x:Key="GridLineColorBrush" Color="#FFCEDFF6" />
<LinearGradientBrush x:Key="AlternateRowBackgroundBrush"
                     StartPoint="0.5,0.0" EndPoint="0.5,1.0">
    <GradientStop Color="#FFFEFEFF" Offset="0"/>
    <GradientStop Color="#FFE4F0FC" Offset="1"/>
</LinearGradientBrush>
These brushes will then be used to set the following properties on the style:
(…)
<Setter Property="Background"
        Value="{StaticResource DefaultControlBackgroundBrush}"/>
<Setter Property="Foreground"
        Value="{StaticResource DefaultControlForegroundBrush}"/>
<Setter Property="BorderBrush"
        Value="{StaticResource DefaultControlBorderBrush}" />
<Setter Property="HorizontalGridLinesBrush"
        Value="{StaticResource GridLineColorBrush}" />
<Setter Property="VerticalGridLinesBrush"
        Value="{StaticResource GridLineColorBrush}" />
<Setter Property="AlternatingRowBackground"
        Value="{StaticResource AlternateRowBackgroundBrush}" />
<Setter Property="BorderThickness" Value="1" />
(…)

In the sample you will find all the style for the DataGrid. When you go through its ControlTemplate you will see most of the items described in ‘Visual breakdown of layout and styles’. This is how our DataGrid currently looks with the new style:

You can download a working sample by following this link.

Styling DataGridColumnHeaders

The next step will be to create custom styles for our DataGridColumnHeaders. In the class diagram above you can see that DataGridColumnHeaders extend ButtonBase, so when we style a DataGridColumnHeader we are actually creating a style for a button. We also need to keep in mind the two styles for the grippers – one for each side of the DataGridColumnHeader. The grippers will be used to resize the DataGridColumnHeader, thus they need to exist as controls the user can interact with!

Let’s start by creating the style for the grippers, both left and right, since they will be referenced as static resources by the DataGridColumnHeader style.

<!-- DataGridColumnHeader Right Gripper Style -->
<Style x:Key="ColumnHeaderRightGripperStyle" 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}">
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<!-- DataGridColumnHeader Left Gripper Style -->
<Style x:Key="ColumnHeaderLeftGripperStyle" 
       BasedOn="{StaticResource ColumnHeaderRightGripperStyle}" 
       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 Name="Border"
                        Padding="{TemplateBinding Padding}" 
                        Background="{TemplateBinding Background}">
                    <Canvas>
                        <Line RenderOptions.EdgeMode="Aliased" Stroke="#88B0E4"
                              X1="7" Y1="{Binding ElementName=Border, Path=ActualHeight}"
                              X2="7" Y2="0"/>
                    </Canvas>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

As you may have noticed we are drawing a line on the left gripper but not drawing it on the right gripper. If we were to draw lines on both sides the end result would be a thicker line. Instead, on the right gripper, we just reserve some space so that the user will have somewhere to click and drag to resize the column.

Now that you have created the grippers you can go ahead and create the style for the DataGridColumnHeader. In this style we will be adding a nice blue gradient background and a highlight gradient that gets displayed when the user put his mouse over a column header:

<!-- DataGridColumnHeader Style -->
<Style x:Key="ColumnHeaderStyle" TargetType="{x:Type WpfToolkit:DataGridColumnHeader}">
    <Setter Property="VerticalContentAlignment" Value="Center" />
    <Setter Property="Background" Value="{StaticResource HeaderBackgroundBrush}"/>
    <Setter Property="BorderBrush" Value="{StaticResource HeaderBorderBrush}" />
    <Setter Property="BorderThickness" Value="0,1,0,1" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type WpfToolkit:DataGridColumnHeader}">
                <Grid>
                    <WpfToolkit:DataGridHeaderBorder
                        x:Name="headerBorder"
                        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}">
                        <Border BorderBrush="{StaticResource HeaderInnerBorderBrush}" 
                                BorderThickness="0,1,0,0">
                            <TextBlock
                                Text="{Binding}" Margin="4,0,4,0"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
                        </Border>
                    </WpfToolkit:DataGridHeaderBorder>

                    <Thumb x:Name="PART_LeftHeaderGripper"
                           HorizontalAlignment="Left"
                           Style="{StaticResource ColumnHeaderRightGripperStyle}"/>
                    <Thumb x:Name="PART_RightHeaderGripper"
                           HorizontalAlignment="Right"
                           Style="{StaticResource ColumnHeaderLeftGripperStyle}"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="headerBorder" Property="Background" 
                                Value="{StaticResource HeaderHighlightedBackgoundBrush}" />
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter TargetName="headerBorder" Property="Background" 
                                Value="{StaticResource HeaderPressedBackgroundBrush}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Go ahead now and create a ‘Brushes.xaml’ beside the ‘DataGrid.Generic.xaml’ resource dictionary. In here you will define all of the brushes used by the styles in the DataGrid. This will make it easier for you to reuse them on the remaining controls of your application.

<!-- Header related brushes -->
<SolidColorBrush x:Key="HeaderBorderBrush" Color="#88B0E4"/>
<SolidColorBrush x:Key="HeaderInnerBorderBrush" Color="#FFFFFF" />
<LinearGradientBrush x:Key="HeaderBackgroundBrush" 
                     StartPoint="0.5,0.0" EndPoint="0.5,1.0">
    <GradientStop Color="#FF98BFEB" Offset="0"/>
    <GradientStop Color="#FFB8D4F2" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HeaderHighlightedBackgoundBrush" 
                     StartPoint="0,0" EndPoint="0,1">
    <GradientStop Color="#FFA3CBF7" Offset="0"/>
    <GradientStop Color="#FFD9E6F9" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HeaderPressedBackgroundBrush" 
                     StartPoint="0,0" EndPoint="0,1">
    <GradientStop Color="#FFA3CBF7" Offset="1"/>
    <GradientStop Color="#FFD9E6F9" Offset="0"/>
</LinearGradientBrush>

In order for you to see the outcome of these new styles you will have to alter the DataGrid style by adding it a setter for the ColumnHeaderStyle property:

<Setter Property="ColumnHeaderStyle" Value="{StaticResource ColumnHeaderStyle}"/>

In the following picture you can see how our DataGrid is actually looking after restyling the DataGridColumnHeaders:

Here are our fancy looking DataGridColumnHeaders. Notice that the ‘Player Name’ column was purposely highlighted when the screenshot was taken.

You can download a working sample of the code presented here by following this link.

Styling DataGridRowHeaders

DataGridRowHeaders pretty much follow the DataGridColumnHeaders in the way they are implemented. So you have two grippers, one on top and another on bottom, and a style for header itself. In this case we will use the same style for both the grippers just to lay the required space for the user to interact with. The visual separator for the columns will be the control template’s border.

<!-- DataGridRowHeader Gripper -->
<Style x:Key="RowHeaderGripperStyle" TargetType="{x:Type Thumb}">
    <Setter Property="Height" Value="8"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Cursor" Value="SizeNS"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Thumb}">
                <Border Padding="{TemplateBinding Padding}"
                        Background="{TemplateBinding Background}"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

 

Now you can go ahead and include the style for the DataGridRowHeader. For this you will use most of the code from the DataGridColumnHeader and the corresponding brushes. We want to keep the look and feel of both header types consistent.

<!-- DataGridRowHeader Style -->
<Style x:Key="{x:Type WpfToolkit:DataGridRowHeader}"
       TargetType="{x:Type WpfToolkit:DataGridRowHeader}">
    <Setter Property="Background" Value="{StaticResource HeaderBackgroundBrush}" />
    <Setter Property="BorderBrush" Value="{StaticResource HeaderBorderBrush}" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type WpfToolkit:DataGridRowHeader}">
                <Grid>
                    <WpfToolkit:DataGridHeaderBorder 
                        x:Name="headerBorder"
                        IsSelected="{TemplateBinding IsRowSelected}"
                        IsHovered ="{TemplateBinding IsMouseOver}"
                        IsPressed="{TemplateBinding IsPressed}"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="1,0,1,1"
                        Padding ="{TemplateBinding Padding}"
                        Orientation="Horizontal"
                        SeparatorVisibility="{TemplateBinding SeparatorVisibility}"
                        SeparatorBrush="{TemplateBinding SeparatorBrush}">
                        <Border BorderBrush="{StaticResource HeaderInnerBorderBrush}"
                                BorderThickness="0,1,0,0">
                            <StackPanel Orientation="Horizontal">
                                <ContentPresenter
                                    SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                    VerticalAlignment="Center"/>
                                <Control
                                    SnapsToDevicePixels="false"
                                    Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type WpfToolkit:DataGridRow}}, Path=(Validation.HasError), Converter={StaticResource bool2VisibilityConverter}}"
                                    Template="{Binding RelativeSource={RelativeSource AncestorType={x:Type WpfToolkit:DataGridRow}}, Path=ValidationErrorTemplate}" />
                            </StackPanel>
                        </Border>
                    </WpfToolkit:DataGridHeaderBorder>
                    
                    <Thumb x:Name="PART_TopHeaderGripper"
                           VerticalAlignment="Top"
                           Style="{StaticResource RowHeaderGripperStyle}"/>
                    <Thumb x:Name="PART_BottomHeaderGripper"
                           VerticalAlignment="Bottom"
                           Style="{StaticResource RowHeaderGripperStyle}"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="headerBorder" Property="Background" 
                                Value="{StaticResource HeaderHighlightedBackgoundBrush}" />
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter TargetName="headerBorder" Property="Background" 
                                Value="{StaticResource HeaderPressedBackgroundBrush}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

As you can see this style is pretty much the same as the one for the DataGridColumnHeader. After these changes this is how our application is looking:

It is looking pretty cool! To download the sample for this part of the tutorial just follow this link.

Creating a new template for the SelectAllButton

The only thing that is currently killing the look of our DataGrid is that top left corner button. This button is used to select all the rows on the DataGrid and its appearance can be altered by setting it on the DataGrid’s style. First you have to create the style for the button:

<!-- SelectAllButton ControlTemplate -->
<ControlTemplate x:Key="SelectAllButtonTemplate" TargetType="{x:Type Button}">
    <Grid>
        <Rectangle x:Name="Border" SnapsToDevicePixels="True"
                   Stroke="{StaticResource HeaderBorderBrush}"
                   Fill="{StaticResource HeaderBackgroundBrush}" />
        <Border SnapsToDevicePixels="True" Margin="1,1,1,0"
                BorderBrush="White" BorderThickness="0,1,0,0" />
        <Polygon x:Name="Arrow"
                 HorizontalAlignment="Right"
                 VerticalAlignment="Bottom"
                 Margin="8,8,3,3"
                 Opacity="0.15"
                 Fill="Black"
                 Stretch="Uniform"
                 Points="0,10 10,10 10,0" />
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter TargetName="Border" Property="Fill"
                    Value="{StaticResource HeaderHighlightedBackgoundBrush}" />
        </Trigger>
        <Trigger Property="IsPressed" Value="True">
            <Setter TargetName="Border" Property="Fill"
                    Value="{StaticResource HeaderPressedBackgroundBrush}" />
        </Trigger>
        <Trigger Property="IsEnabled" Value="False">
            <Setter TargetName="Arrow" Property="Visibility" Value="Collapsed" />
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

The only thing remaining now is to set this template on the corresponding button on the DataGrid style:

<!--Left Column Header Corner -->
(...)
<Button 
    Command="{x:Static WpfToolkit:DataGrid.SelectAllCommand}"
    Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type WpfToolkit:DataGrid}}, Path=CellsPanelHorizontalOffset}"
    Focusable="false"
    Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type WpfToolkit:DataGrid}}, Path=HeadersVisibility, Converter={x:Static WpfToolkit:DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static WpfToolkit:DataGridHeadersVisibility.All}}" 
    Template="{StaticResource SelectAllButtonTemplate}"/>
(...)

 

Congrats! You have now restyled all of the relevant components of the DataGrid. This is the final screenshot of the sample developed on this blog post:

The final sample for this blog post can be downloaded by following this link.

End of Part II

In this part you have seen how to style the look of the DataGrid. You got to know a bit more about the structure used by WPF Toolkit to render its DataGrid and its data.

Don’t miss the next part of this series. We will look into more advanced stuff like styling cells, columns and creating custom DataGridColumns.

53 thoughts on “WPF Toolkit DataGrid, Part II – Custom styling

  1. Pingback: DotNetShoutout
    1. Hi Philipp! Thanks for the feedback. I am glad you liked the blog post.

      Since this was based on actual work, I had to style the SelectAllButton, it made perfect sense to include it in the article if I was to show a complete solution for styling the DataGrid.

  2. Hi,
    That’s a amazing tutorial ! thank for this. I have a question how you can change the design about the scrollbar ? that is possible ? because on all tutorial I’ve seen there are never this possibility.

    1. Hi Emeric! I am glad you liked the tutorial.

      Yes it is possible to change the design of the scrollbar, this is the good thing about WPF – you have complete freedom over how you want your controls to look. I have not include styling of the scroll bar on the tutorial because there is plenty of material out there explaining just that, and it would considerably extend the tutorial.

      If you have downloaded the sample code on this tutorial just add a “Scroolbar.Generic.xaml” resource dictionary beside the “DataGrid.Generic.xaml” and add it to the merged dictionaries list on the top of the “DataGrid.Generic.xaml” file. You can then get a sample style for the scrollbar from ScrollBar ControlTemplate Example which you can customize to match the look and feel of your application.

  3. Hi Samuel,

    How can the vertical scrolling be fixed so that it will work when there are any grouping on the grid and not just disable it? Cause I’m in that situation and the vertical scrolling does not quite work.

    Cheers.

    1. Hi there John,

      I am not sure I have completely understood what you are questioning, although if what you want is to have the DataGrid’s vertical scroll bar always visible independently of how many rows are displayed, you only have to change the DataGrid style and set the visibility of the scroll bar to Visible instead of using the standard binding:


      Replace:
      <ScrollBar Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" ....

      With:
      <ScrollBar Visibility="Visible"....

  4. Hi Samuel,

    In the style for scroll bars you used a trigger that disable scrolling when there are any groups on the grid. Is that for any reason? I have groups on my datagrid rows and the verical scroll does not work properly when the grouping is on. If I turn grouping off is all fine. Do you have any idea on how to fix that.

    Thanks.

  5. I found it. It seems that the ScrollContentPresenter CanContentScroll property needs to be set to False, wich means that the trigger

    does not quite works.

    Thank you anyway.

  6. Is there anyway to use images in the column headers? I understand how to apply a global style across the entire header that is used for every column, but I would like to use an image for a couple of my headers instead of text?
    Thanks,
    Bob

    1. Hi Bob! When it comes to WPF the question is most likely to be “How can I…” than “Is there anyway..” 🙂 In WPF there is always a way!

      The easiest way to do this is for you to create individual styles for each of the columns you want to display images on the headers. In the styles you would just add an Image and lay it out the usual way (probably with a Grid) – actually you could add anything there, even video!

      A cleaner solution would be to extend the DataGridColumns to have a HeaderPicture property and then change the base column header templates to have an Image control bounded to this property.

  7. How do I get the leftover column header to get the same style applied? I don’t have enough columns to fill the grid horizontally. The grid is filled dynamically so I don’t know what size to make it to avoid this.

    Thanks in advanced

  8. @JD

    Hi JD! After looking at the styles that go with WPF Toolkit DataGrid source code I picked the style for the DataGridColumnHeadersPresenter and checked that the left over column header is actually a DataGridColumnHeader that stretches behind the ItemsPresenter that renders the "real" ColumnHeaders.

    In order for you to style the left over column you will have to override the default style provided for the DataGridColumnHeadersPresenter replacing either the background or the actual style of the filler column.

    As an example, just paste this into your DataGrid.generic.xaml on the sample solution above the DataGrid Style:

    <Style x:Key="{x:Type WpfToolkit:DataGridColumnHeadersPresenter}"
           TargetType="{x:Type WpfToolkit:DataGridColumnHeadersPresenter}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type WpfToolkit:DataGridColumnHeadersPresenter}">
                    <Grid>
                        <WpfToolkit:DataGridColumnHeader IsHitTestVisible="False"
                                                         Background="Red"/>
                        <ItemsPresenter />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
  9. Hello,

    why have you made two different ColumnHeaderGripperStyles for Left/Right?

    Left has only a Border element, but the right has a Border + Canvans + Line in it? This is very confusing and not logical. Is there a certain purpose behind that ?

    1. This is part of the style that comes with WPF Toolkit.

      The idea is that each column header can be resized from both sides. On the left side you only place a border so that the user can interact with. On the right you actually draw the gripper, that is why you are required to have a canvas and a line..

  10. Hello,

    I’m trying to build on your sample here (which is great btw). I’ve added a TextBox at the bottom of each ColumnHeader which serves to hold the ‘live’ text filter for the column. What I’d like to do is be able to bind the text in the TextBox to the ‘FilterText’ property on my subclassed DataGridFilterTextColumn.

    So, by setting the FilterText to ‘Foo’ on the Column and setting the HeaderStyle to the one I’ve made, the Text in the TextBox would be ‘Foo’. I hope this is clear enough without having to post a bunch of xaml, and I’m hoping you’ll know how these could be linked together.

    Thank You.

    1. Hi JR! This is a tricky issue. You should probably handle this on your view model binding the values on the TextBoxes back to your ViewModel (or code behind if you do not use MVVM) that then updates the filter. As I have already said, the DataGridColumns do not end up in the Visual Tree so there is no way for you to bind to them. I hope this helps you out!

  11. Samuel

    maybe you can give me a hint on this one:

    I have a styled header which adds a textbox to each column header which is used for filtering the datagrid. All works fine. Now I want to clear the filter by code. How can I get a handle to the filter textbox?

    regards
    Klaus

    1. Hi Klaus,
      Well, you would bind the content of your ColumnHeader TextBoxes to some property on your ViewModel, then you would have full access to the property and would be able to change it programmatically as you wish. Using MVVM makes all this pretty simple!

  12. Awesome! Thank you so much. I have a super nice datagrid now without having to spend days trying to figure it out 🙂 Really helpful for non-designer people.

  13. Samuel

    all grid elements are templated by your really nice solution … no wait,there is something missing: If the datagrid has only 2 columns for example, there is space left from the second column to the right border of the datagrid. And the column header area of this empty space is still “battleship grey”
    I hope you understand my point, how can I retemplate/recolor this area?

    Regards
    Klaus

  14. cool. Nice approach to styling.

    A dumb question since I’m newbie: Why when I select a row I dont have highlighted with blue (like screenshots?).Is something missing in the resources? Thanks.

  15. Hi there,

    Great website, it’s helped me a lot. I’m wondering if you can possibly help me with an issue though. I’m using almost verbatim the same datagrid style you have defined above. My issue is, in my grid I have 3 columns that allow input(IsReadOnly=False) while the others don’t. I would like these 3 to have a different background color than the rest, while maintaining the gradient brush style, and the AlternatingRowBackground pattern.

    For example, in your grid above, the rows alternate between white and a gradient light blue. I’d like to maintain this, except for the input fields would alternate between a really light green and a darker gradient green for example. Do you think this is possible? Thanks in advance!

  16. Wow, nice tutorial about DataGrid I’ve never seen before. But I couldn’t download sample sources. Could you help me to download it?

  17. @Ken You can achieve this by tweaking the code for the DataGridCell style.

    <Style x:Key="CenterAlignedCellStyle" TargetType="{x:Type WpfToolkit:DataGridCell}" >

        <Setter Property="Template">

            <Setter.Value>

                <ControlTemplate TargetType="{x:Type WpfToolkit:DataGridCell}">

                    <Grid Background="{TemplateBinding Background}">

                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>

                        <Border x:Name="backgroundBorder" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />

                    </Grid>

                    <ControlTemplate.Triggers>

                        <Trigger Property="IsReadOnly" Value="True">

                            <Setter TargetName="backgroundBorder" Property="Background" Value="#33000000"/>

                        </Trigger>

                    </ControlTemplate.Triggers>

                </ControlTemplate>

            </Setter.Value>

        </Setter>

    </Style>

    In here we bind to the DataGridCell’s IsReadOnly property in order to give it a darker look when the DataGridCell IsReadOnly (the darkening is accomplished by adding a border on top of the control). If you set the column that applies this DataGridCellStyle to IsReadOnly = false, you will see that your column gets darker without loosing it’s alternating background color.

  18. @Samuel Moura

    If adding sorting pretty straightforward ( up/down arrows ) could you please give some clues. I’d like to keep your themes. Perhaps , you’ve already shown it somewhere else.

  19. Hi Samuel,

    First of all MindBlowing Article..No words to describe..

    Am a newbie to WPF and its really a very good starter kit.

    I need some help from you.I dnt want the Select All Button and that column beneath it.I removed the button from the datagrid.generic.xaml, but the columns are still there.(Meanwhile, am using this grid to make a digital signage, so no need to select all and am refreshing the grid every 1 second).So can you please tell me how to remove the select all and that column completely.

  20. @Renju
    Hi Sam,

    I Found it myself, I dnt know whether its the correct method or not.Anyways, I changed the property of grid headersvisibility = column (before it was ALL)and hurray its gone 🙂

    Also , is there any way to add an image to the background of the grid or to the column header or bothways?

    Thanks buddy..

    PS: Expecting more WPF info from you…

  21. In Visual Studio 2010 with target .Net 4 may I drop all references to WPFToolkit in DataGrid.Generic.xaml

    It is not obvious how to replace

    …xmlns:WpfToolkit=”http://schemas.microsoft.com/wpf/2008/toolkit”
    xmlns:Primitives=”clr-namespace:Microsoft.Windows.Controls.Primitives;assembly=WPFToolkit”>

  22. Not sure whether the only way but changing to

    xmlns:Themes=”clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic”
    xmlns:Primitives=”clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework”>

    produced the same results. Themes for <Themes:DataGridHeaderBorder as without WPFToolkit <DataGridHeaderBorder in XAML becomes invalid.

Leave a Reply

Your email address will not be published. Required fields are marked *