Templating Headers and Cells

RadPivotGrid provides few options to template its cells and headers out of the box. You can either apply one template to all of them using the CellTemplate, RowHeaderTemplate and ColumnHeaderTemplate properties of RadPivotGrid. Or you can use the CellTemplateSelector, RowHeaderTemplateSelector and ColumnHeaderTemplateSelector properties in order to implement custom TemplateSelector and template the headers and cells per condition. This article will show you how to improve the RadPivotGrid appearance by applying custom Templates and implementing custom TemplateSelectors.

Using Custom Cell and Header Templates

The CellTemplate, RowHeaderTemplate and ColumnHeaderTemplate properties of RadPivotGrid will help you to easily apply a custom template to all of the cells or to all of the column and row headers. You would simply need to define the needed DataTemplates and apply them to RadPivotGrid. For example if you need to have green cells and headers with Italic FontStyle you will need to define the following templates:

<UserControl.Resources>      
    <DataTemplate x:Key="CellTemplate"> 
        <Border BorderThickness="1 1 0 0" BorderBrush="LightGray"> 
            <Grid Background="LightGreen"> 
                <TextBlock Text="{Binding Data, Mode=OneWay}" Margin="4" VerticalAlignment="Center" HorizontalAlignment="Right"/> 
            </Grid> 
        </Border> 
    </DataTemplate> 
    <DataTemplate x:Key="HeaderTemplate"> 
        <TextBlock Text="{Binding Data, Mode=OneWay}" FontStyle="Italic" Margin="4 0 0 0"  VerticalAlignment="Center" /> 
    </DataTemplate> 
</UserControl.Resources>   

And apply them as shown below:

<pivot:RadPivotGrid CellTemplate="{StaticResource CellTemplate}"  
                    RowHeaderTemplate="{StaticResource HeaderTemplate}"  
                    ColumnHeaderTemplate="{StaticResource HeaderTemplate}" /> 

Figure 1 demonstrates the final result.

Figure 1: Custom cell and header templates.

Rad Pivot Grid Styles And Templates Templating Cells 03

Using Custom CellTemplateSelector

Implementing a custom CellTemplateSelector allows you to apply different templates per a condition. For example depending on the cell value you can change its Background in order to indicate lower or higher value than a certain one. To get it started you would need to create a new class inheriting from the DataTemplateSelector class and define the two Templates - one for the lower values and one for the higher ones. Afterwards you have to override the SelectTemplate and implement the needed custom logic. So finally the custom CellTemplateSelector should look the following way:

public class CellTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate RedTemplate { get; set; } 
    public DataTemplate GreenTemplate { get; set; } 
 
    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
        var cellAggregate = item as CellAggregateValue; 
 
        if (cellAggregate != null) 
        { 
            var description = cellAggregate.Description as PropertyAggregateDescription; 
 
            if (description.PropertyName == "Net" && cellAggregate.RowGroup.Type == GroupType.BottomLevel && cellAggregate.ColumnGroup.Type == GroupType.BottomLevel) 
            { 
                if (Convert.ToDouble(cellAggregate.Value) > 1000d) 
                { 
                    return this.GreenTemplate; 
                } 
                else 
                { 
                    return this.RedTemplate; 
                } 
            } 
        } 
 
        return base.SelectTemplate(item, container); 
    } 
} 
Public Class CellTemplateSelector 
    Inherits DataTemplateSelector 
 
    Public Property RedTemplate() As DataTemplate 
    Public Property GreenTemplate() As DataTemplate 
 
    Public Overrides Function SelectTemplate(ByVal item As Object, ByVal container As DependencyObject) As DataTemplate 
        Dim cellAggregate = TryCast(item, CellAggregateValue) 
 
        If cellAggregate IsNot Nothing Then 
            Dim description = TryCast(cellAggregate.Description, PropertyAggregateDescription) 
 
            If description.PropertyName = "Net" AndAlso cellAggregate.RowGroup.Type = GroupType.BottomLevel AndAlso cellAggregate.ColumnGroup.Type = GroupType.BottomLevel Then 
                If Convert.ToDouble(cellAggregate.Value) > 1000.0R Then 
                    Return Me.GreenTemplate 
                Else 
                    Return Me.RedTemplate 
                End If 
            End If 
        End If 
 
        Return MyBase.SelectTemplate(item, container) 
    End Function 
End Class 

Next thing to do is to define the required templates in the XAML as shown below:

<UserControl.Resources>         
    <local:CellTemplateSelector x:Key="CellTemplateSelector"> 
        <local:CellTemplateSelector.GreenTemplate> 
            <DataTemplate> 
                <Border BorderThickness="1 1 0 0" BorderBrush="LightGray"> 
                    <Grid Background="LightGreen"> 
                        <TextBlock Text="{Binding Data, Mode=OneWay}" Margin="4" VerticalAlignment="Center" HorizontalAlignment="Right"/> 
                    </Grid> 
                </Border> 
            </DataTemplate> 
        </local:CellTemplateSelector.GreenTemplate> 
        <local:CellTemplateSelector.RedTemplate> 
            <DataTemplate> 
                <Border BorderThickness="1 1 0 0" BorderBrush="LightGray"> 
                    <Grid Background="Red"> 
                        <TextBlock Text="{Binding Data, Mode=OneWay}" Margin="4" VerticalAlignment="Center" HorizontalAlignment="Right"/> 
                    </Grid> 
                </Border> 
            </DataTemplate> 
        </local:CellTemplateSelector.RedTemplate> 
    </local:CellTemplateSelector> 
</UserControl.Resources>   

And the last step would be to assign the CellTemplateSelector to RadPivotGrid:

<pivot:RadPivotGrid x:Name="pivotGrid" CellTemplateSelector="{StaticResource CellTemplateSelector}"/> 

You can see the final result on Figure 2.

Figure 2: Cells with values below 1000 are colored in red and the other cells in green using CellTemplateSelector. Rad Pivot Grid Styles And Templates Templating Cells 01

Find a runnable project of the previous example in the WPF Samples GitHub repository.

Using Custom HeaderTemplateSelectors

By implementing a custom HeaderTemplateSelector you are able to modify the templates only of the column header cells or row header cells. In this section you will see how to add images in the different header cells. Firstly you will need to create custom HeaderTemplateSelector that inherits from DataTemplateSelector and define a DataTemplate which will be used for the Product header cells. The selector should look as shown below:

public class HeaderTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate ProductTemplate { get; set; } 
 
    public override DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container) 
    { 
        FrameworkElement element = container as FrameworkElement; 
        GroupData data = element.DataContext as GroupData; 
        PropertyGroupDescriptionBase pgd = data.GroupDescription as PropertyGroupDescriptionBase; 
 
        if (pgd != null && pgd.PropertyName == "Product") 
        { 
            return this.ProductTemplate; 
        } 
 
        return base.SelectTemplate(item, container); 
    } 
} 
Public Class HeaderTemplateSelector 
    Inherits DataTemplateSelector 
 
    Public Property ProductTemplate() As DataTemplate 
 
    Public Overrides Function SelectTemplate(ByVal item As Object, ByVal container As System.Windows.DependencyObject) As DataTemplate 
        Dim element As FrameworkElement = TryCast(container, FrameworkElement) 
        Dim data As GroupData = TryCast(element.DataContext, GroupData) 
        Dim pgd As PropertyGroupDescriptionBase = TryCast(data.GroupDescription, PropertyGroupDescriptionBase) 
 
        If pgd IsNot Nothing AndAlso pgd.PropertyName = "Product" Then 
            Return Me.ProductTemplate 
        End If 
 
        Return MyBase.SelectTemplate(item, container) 
    End Function 
End Class 

Next thing to do is to define the required templates in the XAML the following way:

<local:ProductToImageConverter x:Key="ProductToImageConverter"/>         
<local:HeaderTemplateSelector x:Key="HeaderTemplateSelector"> 
    <local:HeaderTemplateSelector.ProductTemplate> 
        <DataTemplate> 
            <Grid Height="80"> 
                <Grid.ColumnDefinitions> 
                    <ColumnDefinition Width="64"/> 
                    <ColumnDefinition Width="85"/> 
                </Grid.ColumnDefinitions> 
                <Image Source="{Binding Data, Converter={StaticResource ProductToImageConverter}}"  Stretch="None"/> 
                <TextBlock Grid.Column="1" Text="{Binding Data, Mode=OneWay}" Margin="4 0 0 0"  VerticalAlignment="Center"/> 
            </Grid> 
        </DataTemplate> 
    </local:HeaderTemplateSelector.ProductTemplate> 
</local:HeaderTemplateSelector> 

Using an IValueConverter you will be able to return the path for the needed image depending content of the header cell:

public class ProductToImageConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
        string product = System.Convert.ToString(value); 
        return string.Format("/CustomHeaderTemplate;component/ProductImages/{0}.png", product); 
    } 
 
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
        throw new NotImplementedException(); 
    } 
} 
Public Class ProductToImageConverter 
    Implements IValueConverter 
 
    Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object 
        Dim product As String = System.Convert.ToString(value) 
        Return String.Format("/CustomHeaderTemplate;component/ProductImages/{0}.png", product) 
    End Function 
 
    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object 
        Throw New NotImplementedException() 
    End Function 
End Class 

Finaly you will have to assing the HeaderTemplateSelector to the RowHeaderTemplateSelector and ColumnHeaderTemplateSelector properties of RadPivotGrid.

<pivot:RadPivotGrid RowHeaderTemplateSelector="{StaticResource HeaderTemplateSelector}"  
                    ColumnHeaderTemplateSelector="{StaticResource HeaderTemplateSelector}"/> 

You can see the final result on Figure 3.

Figure 3: Header cells with different images. Rad Pivot Grid Styles And Templates Templating Cells 02

Find a runnable project of the previous example in the WPF Samples GitHub repository.

See Also

In this article