Table of Contents
Item Template & Style

The appearance of an EO.Wpf Menu can be customized through a number of templates. This section covers the following topics:

Customizing Menu Bar Style

Many standard Control properties are directly applied to the menu bar. For example, the following sample sets Background, FontFamily and FontSize to change the background of the menu bar and the font for all menu items.

XAML
<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:eo="http://schemas.essentialobjects.com/wpf/"
        Title="MainWindow" Height="250" Width="350">
    <StackPanel>
        <eo:Menu Background="#ABC7F6" FontFamily="Tahoma" FontSize="20">
            <eo:MenuItem Header="_File"></eo:MenuItem>
            <eo:MenuItem Header="_Help"></eo:MenuItem>
        </eo:Menu>
    </StackPanel>
</Window>

The above code produces the following result:

Customizing Top Level Items

You can customize the appearance of the top level items through TopLevelHeaderTemplate or TopLevelItemTemplate. TopLevelHeaderTemplate applies to top level items that have sub menu items. TopLevelItemTemplate applies to top level items that do not have sub menu items. It is common for these two properties to use the same template.

The following sample demonstrates how to use a custom TopLevelHeaderTemplate:

XAML
<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:eo="http://schemas.essentialobjects.com/wpf/"
        Title="MainWindow" Height="250" Width="350">
    <Window.Resources>
        <!-- Custom Top Level Header/Item Template -->
        <DataTemplate x:Key="TopLevelItemTemplate">
            <Border x:Name="Border" Margin="2" Padding="6,4,6,4">
                <ContentPresenter 
                    Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=Header}"
                    RecognizesAccessKey="True"
                    SnapsToDevicePixels="True"/>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <eo:Menu Background="#ABC7F6" FontFamily="Tahoma" FontSize="11"
            TopLevelHeaderTemplate="{StaticResource TopLevelItemTemplate}"
            TopLevelItemTemplate="{StaticResource TopLevelItemTemplate}">
            <eo:MenuItem Header="_Format"></eo:MenuItem>
            <eo:MenuItem Header="_Layout"></eo:MenuItem>
        </eo:Menu>
    </StackPanel>
</Window>

The above code merely added a Border around the header text, then set the Border's Margin and Padding property to reserve more spaces around the menu item text. This sample applies the same style to both TopLevelHeaderTemplate and TopLevelItemTemplate. The code produces the following result:

Even though the above code changed the appearance of the top level item by applying a custom template, it does not highlight the item when user moves mouse over the item. The following code added a trigger based on the MenuItem's IsMouseOver property to change the border and background color when mouse is over the menu item:

XAML
<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:eo="http://schemas.essentialobjects.com/wpf/"
        Title="MainWindow" Height="250" Width="350">
    <Window.Resources>
        <!-- Custom Top Level Header/Item Template -->
        <DataTemplate x:Key="TopLevelItemTemplate">
            <Border x:Name="Border" Margin="2" Padding="6,4,6,4">
                <ContentPresenter 
                    Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=Header}"
                    RecognizesAccessKey="True"
                    SnapsToDevicePixels="True"/>
            </Border>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=IsMouseOver}" Value="True">
                    <Setter TargetName="Border" Property="Background" Value="#C0D6F4"></Setter>
                    <Setter TargetName="Border" Property="BorderThickness" Value="1"></Setter>
                    <Setter TargetName="Border" Property="BorderBrush" Value="#000080"></Setter>
                    <Setter TargetName="Border" Property="Padding" Value="5,3,5,3"></Setter>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <eo:Menu Background="#ABC7F6" FontFamily="Tahoma" FontSize="11"
            TopLevelHeaderTemplate="{StaticResource TopLevelItemTemplate}"
            TopLevelItemTemplate="{StaticResource TopLevelItemTemplate}">
            <eo:MenuItem Header="_Format"></eo:MenuItem>
            <eo:MenuItem Header="_Layout"></eo:MenuItem>
        </eo:Menu>
    </StackPanel>
</Window>

The above code produces the following result:

Customizing Sub Menu Border and Background

Sub menu border and background can be customized through SubmenuTemplate and SubmenuColumnTemplate. SubmenuTemplate defines the outter frame of the sub menu, while SubmenuColumnTemplate defines the template for each "column". Because each sub menu has at least one column, usually it is necessary to customize both templates in order to customize the appearance of the sub menu. The following code is based on the previous sample and added code for SubmenuTemplate and SubmenuColumnTemplate:

XAML
<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:eo="http://schemas.essentialobjects.com/wpf/"
        Title="MainWindow" Height="250" Width="350">
    <Window.Resources>
        <!-- Custom Top Level Header/Item Template -->
        <DataTemplate x:Key="TopLevelItemTemplate">
            <Border x:Name="Border" Margin="2" Padding="6,4,6,4">
                <ContentPresenter 
                    Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=Header}"
                    RecognizesAccessKey="True"
                    SnapsToDevicePixels="True"/>
            </Border>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=IsMouseOver}" Value="True">
                    <Setter TargetName="Border" Property="Background" Value="#C0D6F4"></Setter>
                    <Setter TargetName="Border" Property="BorderThickness" Value="1"></Setter>
                    <Setter TargetName="Border" Property="BorderBrush" Value="#000080"></Setter>
                    <Setter TargetName="Border" Property="Padding" Value="5,3,5,3"></Setter>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>

        <!-- Custom Sub Menu Template -->
        <DataTemplate x:Key="SubMenuTemplate">
            <Border Background="#F6F6F6"
                BorderBrush="#002D96"
                BorderThickness="1"
                KeyboardNavigation.IsTabStop="false">
                <ContentPresenter x:Name="PART_SubmenuContent" />
            </Border>
        </DataTemplate>

        <!-- Custom Sub Menu Column Template -->
        <DataTemplate x:Key="SubMenuColumnTemplate">
            <Grid>
                <Rectangle
                           HorizontalAlignment="Left"
                           Width="28">
                    <Rectangle.Fill>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                            <GradientStop Offset="0" Color="#f6f6f6"></GradientStop>
                            <GradientStop Offset="1" Color="#87ade4"></GradientStop>
                        </LinearGradientBrush>
                    </Rectangle.Fill>
                </Rectangle>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <eo:Menu Background="#ABC7F6" FontFamily="Tahoma" FontSize="11"
            TopLevelHeaderTemplate="{StaticResource TopLevelItemTemplate}"
            TopLevelItemTemplate="{StaticResource TopLevelItemTemplate}"
            SubmenuTemplate="{StaticResource SubMenuTemplate}"
            SubmenuColumnTemplate="{StaticResource SubMenuColumnTemplate}">
            <eo:MenuItem Header="_Format">
                <eo:MenuItem Header="Styles..."></eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Foreground Color..."></eo:MenuItem>
                <eo:MenuItem Header="Background Color..."></eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Font">
                    <eo:MenuItem Header="Bold" IsChecked="True"></eo:MenuItem>
                    <eo:MenuItem Header="Italic"></eo:MenuItem>
                    <eo:MenuItem Header="Underline"></eo:MenuItem>
                </eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Horizontal Spacing"></eo:MenuItem>
                <eo:MenuItem Header="Vertical Spacing"></eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Order"></eo:MenuItem>
            </eo:MenuItem>
            <eo:MenuItem Header="_Layout"></eo:MenuItem>
        </eo:Menu>
    </StackPanel>
</Window>

Key points of interest in the above code include:

  • SubmenuTemplate defines the outter frame of the whole sub menu;
  • It uses a Border to creates the outside border for the sub menu;
  • It uses a ContentPresenter to display all child menu items. The child items can be in a single column or multiple columns. The name of the ContentPresenter must be PART_SubmenuContent;
  • SubMenuColumnTemplate defines the background of a sub menu column. This templates uses a Rectangle with a LinearGradientBrush background to create a gradient side bar for the sub menu. This sample only uses a single column. If the sub menu were to have multiple columns, then SubMenuColumnTemplate would be repeated for each column.

The above code produces the following result:

Customizing Sub Menu Items

Sub menu item styles can be customized through SubmenuHeaderTemplate and SubmenuItemTemplate. These two styles are similar, except that SubmenuHeaderTemplate displays a sub menu indicator (by default a black triangle) to indicate that this item has child items. The following code is based on the previous example, but use a custom template for both SubmenuHeaderTemplate and SubmenuItemTemplate:

XAML
<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:eo="http://schemas.essentialobjects.com/wpf/"
        Title="MainWindow" Height="250" Width="350">
    <Window.Resources>
        <!-- Custom Top Level Header/Item Template -->
        <DataTemplate x:Key="TopLevelItemTemplate">
            <Border x:Name="Border" Margin="2" Padding="6,4,6,4">
                <ContentPresenter 
                    Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=Header}"
                    RecognizesAccessKey="True"
                    SnapsToDevicePixels="True"/>
            </Border>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=IsMouseOver}" Value="True">
                    <Setter TargetName="Border" Property="Background" Value="#C0D6F4"></Setter>
                    <Setter TargetName="Border" Property="BorderThickness" Value="1"></Setter>
                    <Setter TargetName="Border" Property="BorderBrush" Value="#000080"></Setter>
                    <Setter TargetName="Border" Property="Padding" Value="5,3,5,3"></Setter>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
        
        <!-- Custom Background for Sub Menu Side Bar -->
        <LinearGradientBrush x:Key="SubMenuSideBarBrush" StartPoint="0,0" EndPoint="1,0">
            <GradientStop Offset="0" Color="#f6f6f6"></GradientStop>
            <GradientStop Offset="1" Color="#87ade4"></GradientStop>
        </LinearGradientBrush>

        <!-- Custom Sub Menu Content Template -->
        <ControlTemplate x:Key="SubMenuContentTemplate" TargetType="{x:Type ContentControl}">
            <Border Background="#F6F6F6"
                BorderBrush="#002D96"
                BorderThickness="1"
                KeyboardNavigation.IsTabStop="false">
                <Grid>
                    <Rectangle Fill="{StaticResource SubMenuSideBarBrush}"
                           HorizontalAlignment="Left"
                           Width="28"
                           Margin="2"
                           RadiusX="2"
                           RadiusY="2"/>

                    <ContentPresenter Margin="1,0" />
                </Grid>
            </Border>
        </ControlTemplate>
        
        <!-- Custom Sub Menu Header/Item Template -->
        <DataTemplate x:Key="SubMenuItemTemplate">
            <Grid SnapsToDevicePixels="True">
                <Rectangle Name="Border" Stroke="Transparent" StrokeThickness="1"/>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition MinWidth="24" Width="Auto" SharedSizeGroup="Icon" />
                        <ColumnDefinition Width="Auto" SharedSizeGroup="Text" />
                        <ColumnDefinition Width="17" SharedSizeGroup="SubMenuIndicator" />
                    </Grid.ColumnDefinitions>
                    <ContentPresenter Grid.Column="1" Margin="6"
                                Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=Header}"
                                RecognizesAccessKey="True"
                                SnapsToDevicePixels="True"/>
                    <Path x:Name="SubMenuIndicator" Grid.Column="2"
                      VerticalAlignment="Center"
                      Margin="10,0,0,0"
                      Visibility="Hidden"
                      Fill="Black"
                      Data="M 0,0 L 4,3.5 L 0,7 Z"/>
                </Grid>
            </Grid>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=Role}" Value="SubmenuHeader">
                    <Setter TargetName="SubMenuIndicator" Property="Visibility" Value="Visible"></Setter>    
                </DataTrigger>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=IsMouseOver}" Value="True">
                    <Setter TargetName="Border" Property="Stroke" Value="#000080"></Setter>
                    <Setter TargetName="Border" Property="Fill" Value="#FFEEC2"></Setter>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <eo:Menu Background="#ABC7F6" FontFamily="Tahoma" FontSize="11"
            TopLevelHeaderTemplate="{StaticResource TopLevelItemTemplate}"
            TopLevelItemTemplate="{StaticResource TopLevelItemTemplate}"
            SubmenuContentTemplate="{StaticResource SubMenuContentTemplate}"
            SubmenuHeaderTemplate="{StaticResource SubMenuItemTemplate}"
            SubmenuItemTemplate="{StaticResource SubMenuItemTemplate}">
            <eo:MenuItem Header="_Format">
                <eo:MenuItem Header="Styles..."></eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Foreground Color..."></eo:MenuItem>
                <eo:MenuItem Header="Background Color..."></eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Font">
                    <eo:MenuItem Header="Bold" IsChecked="True"></eo:MenuItem>
                    <eo:MenuItem Header="Italic"></eo:MenuItem>
                    <eo:MenuItem Header="Underline"></eo:MenuItem>
                </eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Horizontal Spacing"></eo:MenuItem>
                <eo:MenuItem Header="Vertical Spacing"></eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Order"></eo:MenuItem>
            </eo:MenuItem>
            <eo:MenuItem Header="_Layout"></eo:MenuItem>
        </eo:Menu>
    </StackPanel>
</Window>

Key points of interest in the above code include:

  • It uses a Grid to define three columns for each item: icon area, text area and sub menu indicator area;
  • The sub menu indicator is invisible by default. It uses a DataTrigger to switch the sub menu indicator's Visibility to Visible if the MenuItem's Role is SubmenuHeader;
  • It also uses a DataTrigger to highlight the MenuItem when the MenuItem's IsMouseOver is true;

The above code produces the following result:

Customizing Separator

Separator can be customized through SeparatorTemplate. The following code added custom template for SeparatorTemplate

XAML
<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:eo="http://schemas.essentialobjects.com/wpf/"
        Title="MainWindow" Height="250" Width="350">
    <Window.Resources>
        <!-- Custom Top Level Header/Item Template -->
        <DataTemplate x:Key="TopLevelItemTemplate">
            <Border x:Name="Border" Margin="2" Padding="6,4,6,4">
                <ContentPresenter 
                    Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=Header}"
                    RecognizesAccessKey="True"
                    SnapsToDevicePixels="True"/>
            </Border>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=IsMouseOver}" Value="True">
                    <Setter TargetName="Border" Property="Background" Value="#C0D6F4"></Setter>
                    <Setter TargetName="Border" Property="BorderThickness" Value="1"></Setter>
                    <Setter TargetName="Border" Property="BorderBrush" Value="#000080"></Setter>
                    <Setter TargetName="Border" Property="Padding" Value="5,3,5,3"></Setter>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
        
        <!-- Custom Background for Sub Menu Side Bar -->
        <LinearGradientBrush x:Key="SubMenuSideBarBrush" StartPoint="0,0" EndPoint="1,0">
            <GradientStop Offset="0" Color="#f6f6f6"></GradientStop>
            <GradientStop Offset="1" Color="#87ade4"></GradientStop>
        </LinearGradientBrush>

        <!-- Custom Sub Menu Content Template -->
        <ControlTemplate x:Key="SubMenuContentTemplate" TargetType="{x:Type ContentControl}">
            <Border Background="#F6F6F6"
                BorderBrush="#002D96"
                BorderThickness="1"
                KeyboardNavigation.IsTabStop="false">
                <Grid>
                    <Rectangle Fill="{StaticResource SubMenuSideBarBrush}"
                           HorizontalAlignment="Left"
                           Width="28"
                           Margin="2"
                           RadiusX="2"
                           RadiusY="2"/>

                    <ContentPresenter Margin="1,0" />
                </Grid>
            </Border>
        </ControlTemplate>
        
        <!-- Custom Sub Menu Header/Item Template -->
        <DataTemplate x:Key="SubMenuItemTemplate">
            <Grid SnapsToDevicePixels="True">
                <Rectangle Name="Border" Stroke="Transparent" StrokeThickness="1"/>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition MinWidth="24" Width="Auto" SharedSizeGroup="Icon" />
                        <ColumnDefinition Width="Auto" SharedSizeGroup="Text" />
                        <ColumnDefinition Width="17" SharedSizeGroup="SubMenuIndicator" />
                    </Grid.ColumnDefinitions>
                    <ContentPresenter Grid.Column="1" Margin="6"
                                Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=Header}"
                                RecognizesAccessKey="True"
                                SnapsToDevicePixels="True"/>
                    <Path x:Name="SubMenuIndicator" Grid.Column="2"
                      VerticalAlignment="Center"
                      Margin="10,0,0,0"
                      Visibility="Hidden"
                      Fill="Black"
                      Data="M 0,0 L 4,3.5 L 0,7 Z"/>
                </Grid>
            </Grid>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=Role}" Value="SubmenuHeader">
                    <Setter TargetName="SubMenuIndicator" Property="Visibility" Value="Visible"></Setter>    
                </DataTrigger>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type eo:MenuItem}}, Path=IsMouseOver}" Value="True">
                    <Setter TargetName="Border" Property="Stroke" Value="#000080"></Setter>
                    <Setter TargetName="Border" Property="Fill" Value="#FFEEC2"></Setter>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
        
        <!-- Custom Separator Template -->
        <DataTemplate x:Key="SeparatorTemplate">
            <Rectangle Height="1" Margin="28,2,0,2" Fill="#6A8CCB"></Rectangle>
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <eo:Menu Background="#ABC7F6" FontFamily="Tahoma" FontSize="11"
            TopLevelHeaderTemplate="{StaticResource TopLevelItemTemplate}"
            TopLevelItemTemplate="{StaticResource TopLevelItemTemplate}"
            SubmenuContentTemplate="{StaticResource SubMenuContentTemplate}"
            SubmenuHeaderTemplate="{StaticResource SubMenuItemTemplate}"
            SubmenuItemTemplate="{StaticResource SubMenuItemTemplate}"
            SeparatorTemplate="{StaticResource SeparatorTemplate}">
            <eo:MenuItem Header="_Format">
                <eo:MenuItem Header="Styles..."></eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Foreground Color..."></eo:MenuItem>
                <eo:MenuItem Header="Background Color..."></eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Font">
                    <eo:MenuItem Header="Bold" IsChecked="True"></eo:MenuItem>
                    <eo:MenuItem Header="Italic"></eo:MenuItem>
                    <eo:MenuItem Header="Underline"></eo:MenuItem>
                </eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Horizontal Spacing"></eo:MenuItem>
                <eo:MenuItem Header="Vertical Spacing"></eo:MenuItem>
                <eo:MenuItem IsSeparator="True"></eo:MenuItem>
                <eo:MenuItem Header="Order"></eo:MenuItem>
            </eo:MenuItem>
            <eo:MenuItem Header="_Layout"></eo:MenuItem>
        </eo:Menu>
    </StackPanel>
</Window>

The above code produces the following result:

Note the light blue color for the separator.