How to set foreground and background colors on a WPF Menu control?

RickNZ picture RickNZ · Dec 9, 2012 · Viewed 23.5k times · Source

I've been working in WPF for quite a while, but there's something basic about styling that I just don't get.

How can I set the foreground and background colors for a Menu control? I started with this:

    <Menu IsMainMenu="True" Background="#FF3A3A3A" Foreground="White">
        <MenuItem Header="_File">
            <MenuItem Header="_Exit">
            </MenuItem>
        </MenuItem>
    </Menu>

The foreground color is apparently inherited by the MenuItem, but the background is not. Next attempt:

    <Menu IsMainMenu="True" Background="#FF3A3A3A" Foreground="White">
        <MenuItem Background="#FF3A3A3A" Header="_File">
            <MenuItem Header="_Exit">
            </MenuItem>
        </MenuItem>
    </Menu>

Now the highlight/overlay colors aren't right when the menu is activated, and I don't see an obvious property to set them. In addition, the menu popup has a wide, white border, and I don't see how to change it's color (or size), either.

What am I missing?

Answer

Thraka picture Thraka · Dec 9, 2012

You will want to learn more about templates and styles in WPF (XAML really). In XAML, how a control looks and how a control operates are two completely different things. In your example, you may have a Foreground and Background property, but the style\template of the control my not utilize these properties for the display of the control.

Read http://wpftutorial.net/Templates.html and http://wpftutorial.net/TemplatesStyles.html, they will give you a good and quick overview. For a more in depth look, read this: http://msdn.microsoft.com/en-us/library/ee230084.aspx

If you are using Visual Studio 2012 to edit your WPF UI, you can easily create a copy of the style\template the menu control is using, and then edit it. If you are using Visual Studio 2010, you should download and install (it may or may not be free) Expression Blend to edit your XAML UI.

Tip: If you are using Visual Studio 2012, make sure your Document Outline window pane is visible all the time. This is very handy for editing a XAML UI. Mine defaulted to being collapsed on the left side of the program. This pane is visible in Expression Blend by default.

Find the MenuItem control in the Document Outline. Right-click on it and select Edit Template->Edit a Copy...

This will create a copy of the existing look-and-feel of the menu item for you to edit. When you do this, you will be in editing mode of that template, to "pop out" of that mode, click on the little icon on the top left of the Document Outline window.

Return Scope Button

When editing the template, you can see the layout and design of the template. When a menu item is being as the drop-down part, it's really displayed like a Popup menu (right click menu). Looking through that template, what pops out at me right away is this color resource named SubMenuBackgroundBrush:

<SolidColorBrush x:Key="SubMenuBackgroundBrush" Color="#FFF5F5F5"/>

If you do a search for SubMenuBackgroundBrush you can see that it is used on a part named PART_Popup:

<Popup x:Name="PART_Popup" AllowsTransparency="true" Focusable="false" HorizontalOffset="1" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" Placement="Bottom" VerticalOffset="-1">
    <Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent">
        <Border x:Name="SubMenuBorder" BorderBrush="#FF959595" BorderThickness="1" Background="{StaticResource SubMenuBackgroundBrush}">
            <ScrollViewer x:Name="SubMenuScrollViewer" Margin="1,0" Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}">
                <Grid RenderOptions.ClearTypeHint="Enabled">
                    <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                        <Rectangle x:Name="OpaqueRect" Fill="{StaticResource SubMenuBackgroundBrush}" Height="{Binding ActualHeight, ElementName=SubMenuBorder}" Width="{Binding ActualWidth, ElementName=SubMenuBorder}"/>
                    </Canvas>
                    <Rectangle Fill="#F1F1F1" HorizontalAlignment="Left" Margin="1,2" RadiusY="2" RadiusX="2" Width="28"/>
                    <Rectangle Fill="#E2E3E3" HorizontalAlignment="Left" Margin="29,2,0,2" Width="1"/>
                    <Rectangle Fill="White" HorizontalAlignment="Left" Margin="30,2,0,2" Width="1"/>
                    <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="true" Margin="2" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
                </Grid>
            </ScrollViewer>
        </Border>
    </Themes:SystemDropShadowChrome>
</Popup>

This is the popup that you see when you right-click on something that shows a menu, or a dropdown menu. Change the references from: {StaticResource SubMenuBackgroundBrush} to {TemplateBinding Foreground}.

When you run the program, you'll see that the main background of the popup has changed, but the area where the icon is displayed has not. These are all the <Rectangle Fill=" items in the popup control too. Change those also. The last reference to Rectangle looks like its the line splitting the icon and the text, you may not what to change that.

Enjoy the wonderful world of templates. It looks confusing and like a lot of work. It is. But when you get the hang of it, it's a very cool system. It's hard to go back to any other UI system after you get the hang of it.