如何在WPF菜单控件上设置前景色和背景色?

14

我已经在WPF上工作了相当长一段时间,但有关样式的基本问题让我非常困惑。

我如何为一个 Menu 控件设置前景色和背景色?我从以下内容开始:

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

前景色显然被MenuItem继承了,但背景色没有。下一次尝试:

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

现在当菜单被激活时,高亮/叠加颜色不正确,我没有看到明显的属性可以设置它们。此外,菜单弹出窗口有一个宽阔的白色边框,我也不知道如何改变它的颜色(或大小)。

我错过了什么?

2个回答

29
你需要学习WPF(实际上是XAML)中的模板和样式。在XAML中,控件的外观和操作是完全不同的两个方面。例如,在你的示例中,可能有前景和背景属性,但是控件的样式/模板可能不使用这些属性来显示控件。
阅读http://wpftutorial.net/Templates.htmlhttp://wpftutorial.net/TemplatesStyles.html,它们会给你一个很好且快速的概述。如果需要更深入的了解,请阅读:http://msdn.microsoft.com/en-us/library/ee230084.aspx 如果你正在使用Visual Studio 2012编辑WPF UI,则可以轻松创建菜单控件正在使用的样式/模板的副本,然后进行编辑。如果您使用的是Visual Studio 2010,则应下载并安装(可能是免费的)Expression Blend来编辑您的XAML UI。
如果您使用的是Visual Studio 2012,请确保您的“文档大纲”窗格始终可见。这对于编辑XAML UI非常方便。我的默认折叠在程序左侧。在Expression Blend中,默认情况下可以看到此窗格。
在“文档大纲”中查找MenuItem控件。右键单击它,然后选择“编辑模板->编辑副本...”。
这将为您创建现有菜单项外观的副本供您编辑。当您这样做时,您将处于该模板的编辑模式中,要“弹出”该模式,请单击Document Outline窗口左上角的小图标。

Return Scope Button

在编辑模板时,您可以查看模板的布局和设计。当菜单项作为下拉部分时,它实际上显示为弹出式菜单(右键菜单)。浏览该模板时,我立即注意到这个名为SubMenuBackgroundBrush的颜色资源:

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

如果您搜索SubMenuBackgroundBrush,您会发现它用于名为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>

这是右键单击显示菜单或下拉菜单时出现的弹出窗口。将引用从{StaticResource SubMenuBackgroundBrush}更改为{TemplateBinding Foreground}
运行程序后,您会发现弹出窗口的主要背景已更改,但显示图标的区域没有更改。这些都是弹出控件中的<Rectangle Fill="项。也要更改这些内容。最后一个对矩形的引用看起来像是分隔图标和文本的线条,您可能不需要更改它。
享受模板的精彩世界。它看起来很混乱,需要很多工作。确实如此。但是一旦掌握了它,它就是一个非常酷的系统。在掌握它之后,很难回到任何其他UI系统。

6
现在我记得为什么一直避免使用模板了。哇,这是多么丑陋、完全不可维护的混乱代码,而实现的本应如此简单(以上回答中的代码只是注入菜单项编辑模板中代码总量的一小部分)。我又回到了默认颜色! - RickNZ
1
它只是看起来那样。实际上并不是这样的。就像你第一次打开一个大型编程项目时一样,你会被所有的文件夹和文件所压倒,不知道该怎么做。随着你更多地使用模板和样式,这对于XAML来说是至关重要的,它将不再像那样。例如,我以前从未看过MenuItem,并且没有使用任何文档,但我能够非常快速地找到调整方法。有助于将该样式存储在应用程序.xaml中,而不是当前父控件xaml中。 - Thraka
1
我知道的。 :) 实际上,弹出菜单没有根据父菜单进行主题设计似乎是控件设计师的疏忽。其他控件比它大得多。当您编辑菜单项时,您正在编辑每个视图的样式。因此,它比简单的“显示文本和颜色”声明更大。它还设置了行为属性,并使用样式(淡出淡入等)连接事件。 - Thraka
1
根据控件的组合方式,您可能只需在样式中覆盖一个设置属性即可。例如,我注意到了SubMenuBackgroundBrush资源的模板声明。如果他们在所有地方都使用它,您可以进行样式覆盖而不是模板覆盖,并声明一个新的画刷资源,只需几行代码即可。但是,由于一些颜色是硬编码的,所以您无法这样做。 - Thraka
同意,改变一些颜色需要太多的代码 - 没有道理。 - RDV
显示剩余2条评论

4

我错过了什么?

控件可以更或少地定制化,有两个级别的控制定制:

  1. 在放置控件的XAML中设置属性,如ForegroundBackground等。
  2. 在你的控件Style中设置Template,并创建自己的ControlTemplate

第二种方法更复杂,但它在让控件外观符合你的要求方面提供了更多的灵活性。如果是这种情况,那么你需要查看默认菜单和菜单项的 ControlTemplate。你可以复制/粘贴它们并根据需要进行修改。

<Window.Resources>
    <Style TargetType="{x:Type Menu}">
        <Setter Property="Template">
            <ControlTemplate TargetType="{x:Type Menu}">
                <!-- your modified template here -->
            </ControlTemplate>
        </Setter>
    </Style>
    <Style TargetType="{x:Type MenuItem}">
        <Setter Property="Template">
            <ControlTemplate TargetType="{x:Type MenuItem}">
                <!-- your modified template here -->
            </ControlTemplate>
        </Setter>
    </Style>
</Window.Resources>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接