MenuItem ControlTemplate Example

Controls in Windows Presentation Foundation (WPF) have a ControlTemplate that contains the visual tree of that control. You can change the structure and appearance of a control by modifying the ControlTemplate of that control. There is no way to replace only part of the visual tree of a control; to change the visual tree of a control you must set the Template property of the control to its new and complete ControlTemplate.

This topic shows the ControlTemplate of the WPF MenuItem control.

This topic contains the following sections.

  • Prerequisites
  • MenuItem ControlTemplate Example
  • Related Topics

Prerequisites

To run the examples in this topic, you should understand how to write WPF applications. For more information, see Getting Started with Windows Presentation Foundation. You should also understand how styles are used in WPF. For more information, see Styling and Templating.

Although this example contains all of the elements that are defined in the ControlTemplate of a MenuItem by default, the specific values should be thought of as examples.

  <Style x:Key="{x:Static MenuItem.SeparatorStyleKey}" TargetType="{x:Type Separator}">
  <Setter Property="Height" Value="1"/>
  <Setter Property="Margin" Value="0,4,0,4"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Separator}">
        <Border BorderBrush="{StaticResource SolidBorderBrush}" BorderThickness="1"/>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

  <!-- TopLevelHeader -->
<ControlTemplate x:Key="{x:Static MenuItem.TopLevelHeaderTemplateKey}" TargetType="{x:Type MenuItem}">
  <Border Name="Border" >
    <Grid>
      <ContentPresenter 
        Margin="6,3,6,3" 
        ContentSource="Header"
        RecognizesAccessKey="True" />
      <Popup 
        Name="Popup"
        Placement="Bottom"
        IsOpen="{TemplateBinding IsSubmenuOpen}"
        AllowsTransparency="True" 
        Focusable="False"
        PopupAnimation="Fade">
        <Border 
          Name="SubmenuBorder"
          SnapsToDevicePixels="True"
          Background="{StaticResource WindowBackgroundBrush}"
          BorderBrush="{StaticResource SolidBorderBrush}"
          BorderThickness="1" >
          <ScrollViewer CanContentScroll="True" 
            Style="{StaticResource MenuScrollViewer}">
            <StackPanel   
            IsItemsHost="True" 
            KeyboardNavigation.DirectionalNavigation="Cycle" />
          </ScrollViewer>
        </Border>
      </Popup>
    </Grid>
  </Border>
  <ControlTemplate.Triggers>
    <Trigger Property="IsSuspendingPopupAnimation" Value="true">
      <Setter TargetName="Popup" Property="PopupAnimation" Value="None"/>
    </Trigger>
    <Trigger Property="IsHighlighted" Value="true">
      <Setter TargetName="Border" Property="Background" Value="{StaticResource NormalBrush}"/>
      <Setter TargetName="Border" Property="BorderBrush" Value="Transparent"/>
    </Trigger>
    <Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="True">
      <Setter TargetName="SubmenuBorder" Property="CornerRadius" Value="0,0,4,4"/>
      <Setter TargetName="SubmenuBorder" Property="Padding" Value="0,0,0,3"/>
    </Trigger>
      <Trigger Property="IsEnabled" Value="False">
      <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>
<!-- TopLevelItem -->

<ControlTemplate 
  x:Key="{x:Static MenuItem.TopLevelItemTemplateKey}" 
  TargetType="{x:Type MenuItem}">
  <Border Name="Border" >
    <Grid>
      <ContentPresenter 
        Margin="6,3,6,3" 
        ContentSource="Header"
        RecognizesAccessKey="True" />
    </Grid>
  </Border>
  <ControlTemplate.Triggers>
    <Trigger Property="IsHighlighted" Value="true">
      <Setter TargetName="Border" Property="Background" Value="{StaticResource NormalBrush}"/>
      <Setter TargetName="Border" Property="BorderBrush" Value="Transparent"/>
    </Trigger>
    <Trigger Property="IsEnabled" Value="False">
      <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

<!-- SubmenuItem -->

<ControlTemplate 
  x:Key="{x:Static MenuItem.SubmenuItemTemplateKey}" 
  TargetType="{x:Type MenuItem}">
  <Border Name="Border" >
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" SharedSizeGroup="Icon"/>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" SharedSizeGroup="Shortcut"/>
        <ColumnDefinition Width="13"/>
      </Grid.ColumnDefinitions>
      <ContentPresenter 
        Name="Icon"
        Margin="6,0,6,0"
        VerticalAlignment="Center"
        ContentSource="Icon"/>
      <Border 
        Name="Check"  
        Width="13" Height="13" 
        Visibility="Collapsed"
        Margin="6,0,6,0" 
        Background="{StaticResource NormalBrush}"
        BorderThickness="1"
        BorderBrush="{StaticResource NormalBorderBrush}">
        <Path 
          Name="CheckMark"
          Width="7" Height="7" 
          Visibility="Hidden" 
          SnapsToDevicePixels="False" 
          Stroke="{StaticResource GlyphBrush}"
          StrokeThickness="2"
          Data="M 0 0 L 7 7 M 0 7 L 7 0" />
      </Border>
      <ContentPresenter 
        Name="HeaderHost"
        Grid.Column="1"
        ContentSource="Header"
        RecognizesAccessKey="True"/>
      <TextBlock x:Name="InputGestureText"
        Grid.Column="2"
        Text="{TemplateBinding InputGestureText}"
        Margin="5,2,0,2"
        DockPanel.Dock="Right" />
    </Grid>
  </Border>
  <ControlTemplate.Triggers>
    <Trigger Property="Icon" Value="{x:Null}">
      <Setter TargetName="Icon" Property="Visibility" Value="Hidden"/>
    </Trigger>
    <Trigger Property="IsChecked" Value="true">
      <Setter TargetName="CheckMark" Property="Visibility" Value="Visible"/>
    </Trigger>
    <Trigger Property="IsCheckable" Value="true">
      <Setter TargetName="Check" Property="Visibility" Value="Visible"/>
      <Setter TargetName="Icon" Property="Visibility" Value="Hidden"/>
    </Trigger>
    <Trigger Property="IsHighlighted" Value="true">
      <Setter TargetName="Border" Property="Background" Value="{StaticResource SelectedBackgroundBrush}"/>
    </Trigger>
    <Trigger Property="IsEnabled" Value="false">
      <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

<!-- SubmenuHeader -->

<ControlTemplate 
  x:Key="{x:Static MenuItem.SubmenuHeaderTemplateKey}" 
  TargetType="{x:Type MenuItem}">
  <Border Name="Border" >
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" SharedSizeGroup="Icon"/>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" SharedSizeGroup="Shortcut"/>
        <ColumnDefinition Width="13"/>
      </Grid.ColumnDefinitions>
      <ContentPresenter 
        Name="Icon"
        Margin="6,0,6,0"
        VerticalAlignment="Center"
        ContentSource="Icon"/>
      <ContentPresenter 
        Name="HeaderHost"
        Grid.Column="1"
        ContentSource="Header"
        RecognizesAccessKey="True"/>
      <TextBlock x:Name="InputGestureText"
        Grid.Column="2"
        Text="{TemplateBinding InputGestureText}"
        Margin="5,2,2,2"
        DockPanel.Dock="Right"/>
      <Path 
        Grid.Column="3"
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Data="M 0 0 L 0 7 L 4 3.5 Z" 
        Fill="{StaticResource GlyphBrush}" />
      <Popup 
        Name="Popup"
        Placement="Right"
        HorizontalOffset="-4" 
        IsOpen="{TemplateBinding IsSubmenuOpen}"
        AllowsTransparency="True" 
        Focusable="False"
        PopupAnimation="Fade">
        <Border 
          Name="SubmenuBorder"
          SnapsToDevicePixels="True"
          Background="{StaticResource WindowBackgroundBrush}"
          BorderBrush="{StaticResource SolidBorderBrush}"
          BorderThickness="1" >
          <ScrollViewer CanContentScroll="True"
            Style="{StaticResource MenuScrollViewer}">
            <StackPanel  
            IsItemsHost="True" 
            KeyboardNavigation.DirectionalNavigation="Cycle" />
          </ScrollViewer>
        </Border>
      </Popup>
    </Grid>
  </Border>

  <ControlTemplate.Triggers>
    <Trigger Property="Icon" Value="{x:Null}">
      <Setter TargetName="Icon" Property="Visibility" Value="Collapsed"/>
    </Trigger>
    <Trigger Property="IsHighlighted" Value="true">
      <Setter TargetName="Border" Property="Background" Value="{StaticResource SelectedBackgroundBrush}"/>
    </Trigger>
              <Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="True">
      <Setter TargetName="SubmenuBorder" Property="CornerRadius" Value="4"/>
      <Setter TargetName="SubmenuBorder" Property="Padding" Value="0,3,0,3"/>
    </Trigger>
    <Trigger Property="IsEnabled" Value="false">
      <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

<!-- MenuItem Style -->

<Style x:Key="{x:Type MenuItem}" TargetType="{x:Type MenuItem}">
  <Setter Property="OverridesDefaultStyle" Value="True"/>
  <Style.Triggers>
    <Trigger Property="Role" Value="TopLevelHeader">
      <Setter Property="Template" Value="{StaticResource {x:Static MenuItem.TopLevelHeaderTemplateKey}}"/>
      <Setter Property="Grid.IsSharedSizeScope" Value="true"/>
    </Trigger>
    <Trigger Property="Role" Value="TopLevelItem">
      <Setter Property="Template" Value="{StaticResource {x:Static MenuItem.TopLevelItemTemplateKey}}"/>
    </Trigger>
    <Trigger Property="Role" Value="SubmenuHeader">
      <Setter Property="Template" Value="{StaticResource {x:Static MenuItem.SubmenuHeaderTemplateKey}}"/>
    </Trigger>
    <Trigger Property="Role" Value="SubmenuItem">
      <Setter Property="Template" Value="{StaticResource {x:Static MenuItem.SubmenuItemTemplateKey}}"/>
    </Trigger>
  </Style.Triggers>
</Style>

The preceding example uses one or more of the following resources.

<!-- Fill Brushes -->

<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#FFF" Offset="0.0"/>
      <GradientStop Color="#CCC" Offset="1.0"/>
    </GradientStopCollection>
  </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="HorizontalNormalBrush" StartPoint="0,0" EndPoint="1,0">
  <GradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#FFF" Offset="0.0"/>
      <GradientStop Color="#CCC" Offset="1.0"/>
    </GradientStopCollection>
  </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="LightBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#FFF" Offset="0.0"/>
      <GradientStop Color="#EEE" Offset="1.0"/>
    </GradientStopCollection>
  </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="HorizontalLightBrush" StartPoint="0,0" EndPoint="1,0">
  <GradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#FFF" Offset="0.0"/>
      <GradientStop Color="#EEE" Offset="1.0"/>
    </GradientStopCollection>
  </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="DarkBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#FFF" Offset="0.0"/>
      <GradientStop Color="#AAA" Offset="1.0"/>
    </GradientStopCollection>
  </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="PressedBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#BBB" Offset="0.0"/>
      <GradientStop Color="#EEE" Offset="0.1"/>
      <GradientStop Color="#EEE" Offset="0.9"/>
      <GradientStop Color="#FFF" Offset="1.0"/>
    </GradientStopCollection>
  </GradientBrush.GradientStops>
</LinearGradientBrush>

<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />

<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />

<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />

<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />

<!-- Border Brushes -->

<LinearGradientBrush x:Key="NormalBorderBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#CCC" Offset="0.0"/>
      <GradientStop Color="#444" Offset="1.0"/>
    </GradientStopCollection>
  </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="HorizontalNormalBorderBrush" StartPoint="0,0" EndPoint="1,0">
  <GradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#CCC" Offset="0.0"/>
      <GradientStop Color="#444" Offset="1.0"/>
    </GradientStopCollection>
  </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="DefaultedBorderBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#777" Offset="0.0"/>
      <GradientStop Color="#000" Offset="1.0"/>
    </GradientStopCollection>
  </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="PressedBorderBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#444" Offset="0.0"/>
      <GradientStop Color="#888" Offset="1.0"/>
    </GradientStopCollection>
  </GradientBrush.GradientStops>
</LinearGradientBrush>

<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />

<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />

<SolidColorBrush x:Key="LightBorderBrush" Color="#AAA" />

<!-- Miscellaneous Brushes -->
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />

<SolidColorBrush x:Key="LightColorBrush" Color="#DDD" />

For the complete sample, see Styling with ControlTemplates Sample.

See Also

Concepts

Guidelines for Designing Stylable Controls

Menu ControlTemplate Example

Other Resources

ControlTemplate Examples