views:

9248

answers:

3

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 Image

Example Code:

<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  A: 

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.

Micah
How would I go about accessing this property? It would be nice if I could just override that one property. I tried doing it through C# code using something like "this.FindResource("Part_Popup)", but it can't find the resource.
Try myMenu.Template.FindName("Part_Popup", this);
Micah
I get an InvaildOperationException: This operation is valid only on elements that have this template applied. I tried replacing "this" with the menu and that doesn't work either.
+2  A: 

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"&gt;
  <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>
Nate
+1  A: 

Thanks for this. Now my question is, how does one set the background color of the submenu icon column inside the Control Template?

If this line shows the submenu items,

how do I specify the background color of the submenu icon column? Let's say I want it to be like Visual Studio of Microsoft Word XP SP2. If you click on any menu you notice that the icon has a dark gray 3-d gradient behind it, whereas the header has a light gray background. How can I accomplish this look?

tina