WPF C# - Change the brush of a menu's background


Question

Does anyone know how to change the brush for a menu's background? This sounds simple, but I don't see any obvious way to do this. You'd think that the Background property would change it, but it doesn't.

Here's what my menu looks like (notice the default white background):

Example Code:

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">

<Window.Resources>
    <SolidColorBrush x:Key="menuItemBrush"
                     Color="#FF505050" />
</Window.Resources>

<Grid x:Name="mainGrid"
      Background="#FF252525">

    <Menu x:Name="mainMenu"
          Background="{DynamicResource menuItemBrush}"
          Grid.ColumnSpan="2"
          VerticalAlignment="Top">

        <MenuItem x:Name="fileMenu"
                  Background="{DynamicResource menuItemBrush}"
                  Foreground="White"
                  Header="File">

            <MenuItem x:Name="fileOpenMenuItem"
                      Background="{DynamicResource menuItemBrush}"
                      Foreground="White"
                      Header="Open..." />

            <MenuItem x:Name="fileSaveMenuItem"
                      Background="{DynamicResource menuItemBrush}"
                      Foreground="White"
                      Header="Save" />

            <MenuItem x:Name="fileSaveAsMenuItem"
                      Background="{DynamicResource menuItemBrush}"
                      Foreground="White"
                      Header="Save As..." />

            <Separator Style="{DynamicResource menuItemSeperator}" />

            <MenuItem x:Name="fileExitMenuItem"
                      Background="{DynamicResource menuItemBrush}"
                      Foreground="White"
                      Header="Exit" />
        </MenuItem>
    </Menu>
</Grid>

1
10
8/13/2017 9:27:44 AM

Accepted Answer

I'd suggest using a tool called kaxaml for writing styles. It includes several code snippets, a color picker and a nice way to instantly see what changes in the xaml code does. Here is a full menu style for what you are trying to do. Just change the brush colors at the top to suit to your needs.

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Page.Resources>

  <!--**************************
    * STYLE: MenuItem
    ************************** -->
  <SolidColorBrush x:Key="HighlightedBackgroundBrush" Color="#FF797878" />
  <SolidColorBrush x:Key="MenuBackgroundBrush" Color="#FF505050" />
  <SolidColorBrush x:Key="NormalBorderBrush" Color="#FFFFFFFF" />
  <SolidColorBrush x:Key="SolidMenuFontBrush" Color="#FFFFFFFF" />
  <SolidColorBrush x:Key="HighlightedText" Color="#FFFFFFFF" />
  <Style x:Key="{x:Type Menu}" TargetType="{x:Type Menu}">
    <Setter Property="OverridesDefaultStyle" Value="True"/>
    <Setter Property="SnapsToDevicePixels" Value="True"/>
    <Setter Property="Height" Value="25"/>
    <Setter Property="Foreground" Value="{StaticResource SolidMenuFontBrush}"/>
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type Menu}">
          <Border
            Background="{StaticResource MenuBackgroundBrush}"
            BorderBrush="{StaticResource MenuBackgroundBrush}"
            BorderThickness="1">
            <StackPanel ClipToBounds="True" Orientation="Horizontal" IsItemsHost="True"/>
          </Border>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
  <Style x:Key="{x:Type MenuItem}" TargetType="{x:Type MenuItem}">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type MenuItem}">
          <Border x:Name="Border"
                  Background="{TemplateBinding Background}"
                  BorderBrush="{TemplateBinding BorderBrush}"
                  BorderThickness="1">
            <Grid>
              <Grid.ColumnDefinitions>
                <ColumnDefinition x:Name="Col0" MinWidth="17" Width="Auto" SharedSizeGroup="MenuItemIconColumnGroup"/>
                <ColumnDefinition Width="Auto" SharedSizeGroup="MenuTextColumnGroup"/>
                <ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemIGTColumnGroup"/>
                <ColumnDefinition x:Name="Col3" Width="14"/>
              </Grid.ColumnDefinitions>

              <!-- ContentPresenter to show an Icon if needed -->
              <ContentPresenter Grid.Column="0" Margin="4,0,6,0" x:Name="Icon" VerticalAlignment="Center" ContentSource="Icon"/>

              <!-- Glyph is a checkmark if needed for a checkable menu -->
              <Grid Grid.Column="0" Visibility="Hidden" Margin="4,0,6,0" x:Name="GlyphPanel" VerticalAlignment="Center">
                <Path x:Name="GlyphPanelpath" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}" Data="M0,2 L0,4.8 L2.5,7.4 L7.1,2.8 L7.1,0 L2.5,4.6 z" FlowDirection="LeftToRight"/>
              </Grid>

              <!-- Content for the menu text etc -->
              <ContentPresenter Grid.Column="1"
                                Margin="{TemplateBinding Padding}"
                                x:Name="HeaderHost"
                                RecognizesAccessKey="True"
                                ContentSource="Header"/>

              <!-- Content for the menu IGT -->
              <ContentPresenter Grid.Column="2"
                                Margin="8,1,8,1"
                                x:Name="IGTHost"
                                ContentSource="InputGestureText"
                                VerticalAlignment="Center"/>

              <!-- Arrow drawn path which points to the next level of the menu -->
              <Grid Grid.Column="3" Margin="4,0,6,0" x:Name="ArrowPanel" VerticalAlignment="Center">
                <Path x:Name="ArrowPanelPath" HorizontalAlignment="Right" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}" Data="M0,0 L0,8 L4,4 z"/>
              </Grid>

              <!-- The Popup is the body of the menu which expands down or across depending on the level of the item -->
              <Popup IsOpen="{Binding Path=IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" x:Name="SubMenuPopup" Focusable="false" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}">
                <Border x:Name="SubMenuBorder" BorderBrush="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Menu}}}" BorderThickness="1" Padding="2,2,2,2">
                  <Grid x:Name="SubMenu" Grid.IsSharedSizeScope="True">
                    <!-- StackPanel holds children of the menu. This is set by IsItemsHost=True -->
                    <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle"/>
                  </Grid>
                </Border>
              </Popup>
            </Grid>
          </Border>

          <!-- These triggers re-configure the four arrangements of MenuItem to show different levels of menu via Role -->
          <ControlTemplate.Triggers>
            <!-- Role = TopLevelHeader : this is the root menu item in a menu; the Popup expands down -->
            <Trigger Property="Role" Value="TopLevelHeader">
              <Setter Property="Padding" Value="6,1,6,1"/>
              <Setter Property="Placement" Value="Bottom" TargetName="SubMenuPopup"/>
              <Setter Property="MinWidth" Value="0" TargetName="Col0"/>
              <Setter Property="Width" Value="Auto" TargetName="Col3"/>
              <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/>
              <Setter Property="Visibility" Value="Collapsed" TargetName="GlyphPanel"/>
              <Setter Property="Visibility" Value="Collapsed" TargetName="IGTHost"/>
              <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
            </Trigger>

            <!-- Role = TopLevelItem :  this is a child menu item from the top level without any child items-->
            <Trigger Property="Role" Value="TopLevelItem">
              <Setter Property="Padding" Value="6,1,6,1"/>
              <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
            </Trigger>

            <!-- Role = SubMenuHeader : this is a child menu item which does not have children -->
            <Trigger Property="Role" Value="SubmenuHeader">
              <Setter Property="DockPanel.Dock" Value="Top"/>
              <Setter Property="Padding" Value="0,2,0,2"/>
            </Trigger>

            <!-- Role = SubMenuItem : this is a child menu item which has children-->
            <Trigger Property="Role" Value="SubmenuItem">
              <Setter Property="DockPanel.Dock" Value="Top"/>
              <Setter Property="Padding" Value="0,2,0,2"/>
              <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
            </Trigger>
            <Trigger Property="IsSuspendingPopupAnimation" Value="true">
              <Setter Property="PopupAnimation" Value="None" TargetName="SubMenuPopup"/>
            </Trigger>

            <!-- If no Icon is present the we collapse the Icon Content -->
            <Trigger Property="Icon" Value="{x:Null}">
              <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/>
            </Trigger>

            <!-- The GlyphPanel contains the CheckMark -->
            <Trigger Property="IsChecked" Value="true">
              <Setter Property="Visibility" Value="Visible" TargetName="GlyphPanel"/>
              <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/>
            </Trigger>

            <!-- Using the system colors for the Menu Highlight and IsEnabled-->
            <Trigger Property="IsHighlighted" Value="true">
              <Setter Property="Background" Value="{StaticResource HighlightedBackgroundBrush}" TargetName="Border"/>
              <Setter Property="Foreground" Value="{StaticResource HighlightedText}"/>
              <Setter Property="BorderBrush" Value="{StaticResource NormalBorderBrush}" TargetName="Border"/>
            </Trigger>
            <Trigger Property="IsHighlighted" Value="false">
              <Setter Property="Background" Value="{StaticResource MenuBackgroundBrush}" TargetName="Border"/>
              <Setter Property="Foreground" Value="{StaticResource SolidMenuFontBrush}"/>
              <Setter Property="BorderBrush" Value="{StaticResource MenuBackgroundBrush}" TargetName="Border"/>
            </Trigger>
            <Trigger Property="IsEnabled" Value="false">
              <Setter Property="Foreground" Value="LightGray"/>
            </Trigger>
          </ControlTemplate.Triggers>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
  </Page.Resources>
<Grid x:Name="mainGrid"
      Background="#FF252525">

    <Menu x:Name="mainMenu"
          Grid.ColumnSpan="2"
          VerticalAlignment="Top">

        <MenuItem x:Name="fileMenu"
                  Header="File">

            <MenuItem x:Name="fileOpenMenuItem"
                      Header="Open..." />

            <MenuItem x:Name="fileSaveMenuItem"
                      Header="Save" />

            <MenuItem x:Name="fileSaveAsMenuItem"
                      Background="{DynamicResource menuItemBrush}"
                      Header="Save As..." />
        </MenuItem>
    </Menu>
  </Grid>
</Page>
11
2/6/2009 3:47:53 AM

You can't do it without overriding the template for the menu item. Deep inside the template is a control called "Part_Popup". You need to change it's background color.


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon