WPF 子菜单样式

发布于 2024-09-12 17:11:36 字数 2340 浏览 8 评论 0原文

如果我向菜单项添加子菜单,则子菜单的样式不正确。此时只能设置菜单项的样式,而不能设置实际的子菜单的样式。因此,无法替换 IsMouseOver 样式,该样式默认为 Windows 上启用的任何主题。

如何设计子菜单的样式?


    <Style TargetType="{x:Type MenuItem}">
        <Setter Property="Background" Value="#0f3c5a"></Setter>
        <Setter Property="Foreground" Value="White"></Setter>
        <Style.Triggers>
            <Trigger Property="IsHighlighted" Value="True">
                <Setter Property="Background" Value="Black"></Setter>
            </Trigger>
            <Trigger Property="IsEnabled" Value="False">
                <Setter Property="Foreground" Value="LightGray"></Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
    <Style TargetType="{x:Type ContextMenu}">
        <Setter Property="OverridesDefaultStyle" Value="True"/>
        <Setter Property="SnapsToDevicePixels" Value="True"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContextMenu}">
                    
                    <!--Here is where you change the border thickness to zero on the menu-->
                    <Border BorderThickness="0" x:Name="Border"  >
                     <StackPanel ClipToBounds="True" Orientation="Vertical"
                     IsItemsHost="True"/>
                     </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter TargetName="Border" Property="Background" Value="#5082a4" />
                        </Trigger>
                    </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

然后像这样的菜单

<ContextMenu Closed="ContextMenu_Closed"  >
    <MenuItem  Command="k:Window1.NewCommand" > 
       <MenuItem  Command="k:Window1.DeleteCommand"/> 
    </MenuItem>
    ...

NewCommand 层上的所有内容都设置了正确的样式,进入 NewCommand 来查看 DeleteCommand MenuItem 本身的样式设置正确,但实际的菜单默认为 Windows 主题样式,我看不出有什么办法可以覆盖它,所以远的。最重要的部分是让子菜单的 IsMouseOver 保持与主菜单结构相同的外观和感觉。

If I add a submenu to a menu item, then the submenu is not being styled properly. One can only style the menuitem at this point, and not the actual sub menu. Hence one can't replace the IsMouseOver styling which then just defaults to whatever theme is enabled on windows.

How can one style the submenu?


    <Style TargetType="{x:Type MenuItem}">
        <Setter Property="Background" Value="#0f3c5a"></Setter>
        <Setter Property="Foreground" Value="White"></Setter>
        <Style.Triggers>
            <Trigger Property="IsHighlighted" Value="True">
                <Setter Property="Background" Value="Black"></Setter>
            </Trigger>
            <Trigger Property="IsEnabled" Value="False">
                <Setter Property="Foreground" Value="LightGray"></Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
    <Style TargetType="{x:Type ContextMenu}">
        <Setter Property="OverridesDefaultStyle" Value="True"/>
        <Setter Property="SnapsToDevicePixels" Value="True"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContextMenu}">
                    
                    <!--Here is where you change the border thickness to zero on the menu-->
                    <Border BorderThickness="0" x:Name="Border"  >
                     <StackPanel ClipToBounds="True" Orientation="Vertical"
                     IsItemsHost="True"/>
                     </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter TargetName="Border" Property="Background" Value="#5082a4" />
                        </Trigger>
                    </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

and then something like this for the menu

<ContextMenu Closed="ContextMenu_Closed"  >
    <MenuItem  Command="k:Window1.NewCommand" > 
       <MenuItem  Command="k:Window1.DeleteCommand"/> 
    </MenuItem>
    ...

Everything on the NewCommand layer is styled properly, going inside NewCommand to view DeleteCommand the MenuItem itself is styled properly, but the actual menu is defaulting to the Windows theme styling and I see no way over overwriting that so far. The most important part is to get the IsMouseOver of submenu's to maintain the same look and feel as the main menu structure.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

行至春深 2024-09-19 17:11:36

正如所承诺的,这是代码。感谢您的帮助 Jay,引导我朝着正确的方向最终在 MSDN 上找到答案 http://msdn.microsoft.com/en-us/library/ms752296.aspx MenuItem 和ContextMenu 控制基本菜单的样式,另外两个用于子菜单项。杰伊的方法也许有效,但不幸的是我没能实现。不过,这工作得很好,并且可能允许对子菜单样式进行更多控制。

    <UserControl.Resources>

    <!-- Separator -->
    <Style TargetType="{x:Type Separator}"
           x:Key="SeparatorStyle">
        <Setter Property="Height"
                Value="1" />
        <Setter Property="Background"
                Value="#0f3c5a" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Separator}">
                    <Rectangle Height="{TemplateBinding Height}"
                               Fill="White" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--Outer menu items-->
    <Style TargetType="{x:Type MenuItem}">
        <Setter Property="Background"
                Value="#0f3c5a"></Setter>
        <Setter Property="Foreground"
                Value="White"></Setter>
        <Style.Triggers>
            <Trigger Property="IsHighlighted"
                     Value="True">
                <Setter Property="Background"
                        Value="Black"></Setter>
            </Trigger>
            <Trigger Property="IsEnabled"
                     Value="False">
                <Setter Property="Foreground"
                        Value="LightGray"></Setter>
            </Trigger>
        </Style.Triggers>
    </Style>

    <!-- Outer menu -->
    <Style TargetType="{x:Type ContextMenu}">
        <Setter Property="OverridesDefaultStyle"
                Value="True" />
        <Setter Property="SnapsToDevicePixels"
                Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContextMenu}">

                    <!--Here is where you change the border thickness to zero on the menu-->
                    <Border BorderThickness="0"
                            x:Name="Border"
                            Background="Transparent">
                        <StackPanel ClipToBounds="True"
                                    Orientation="Vertical"
                                    IsItemsHost="True" />
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver"
                                 Value="true">
                            <Setter TargetName="Border"
                                    Property="Background"
                                    Value="#0f3c5a" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- 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="#0f3c5a"
                        BorderThickness="1"
                        BorderBrush="#5082a4">
                    <Path Name="CheckMark"
                          Width="7"
                          Height="7"
                          Visibility="Hidden"
                          SnapsToDevicePixels="False"
                          Stroke="#5082a4"
                          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="#5082a4" />
            </Trigger>
            <Trigger Property="IsEnabled"
                     Value="false">
                <Setter Property="Foreground"
                        Value="#0f3c5a" />
            </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="#0f3c5a" />
                <Popup Name="Popup"
                       Placement="Right"
                       HorizontalOffset="-4"
                       IsOpen="{TemplateBinding IsSubmenuOpen}"
                       AllowsTransparency="True"
                       Focusable="False"
                       PopupAnimation="Fade">
                    <Border Name="SubmenuBorder"
                            SnapsToDevicePixels="True"
                            Background="#0f3c5a"
                            BorderBrush="#0f3c5a"
                            BorderThickness="1">
                        <StackPanel IsItemsHost="True"
                                    KeyboardNavigation.DirectionalNavigation="Cycle" />
                    </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="#5082a4" />
            </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="#0f3c5a" />
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

As promised, here's the code. Thanks for your help Jay, lead me in the right direction to finally find an answer on MSDN http://msdn.microsoft.com/en-us/library/ms752296.aspx MenuItem and ContextMenu control the styling for the base menu, and the other two are for the submenu items. Jay's way may have worked, but I couldn't get it to unfortunately. This works perfectly though, and probably allows for much more control over the submenus styling.

    <UserControl.Resources>

    <!-- Separator -->
    <Style TargetType="{x:Type Separator}"
           x:Key="SeparatorStyle">
        <Setter Property="Height"
                Value="1" />
        <Setter Property="Background"
                Value="#0f3c5a" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Separator}">
                    <Rectangle Height="{TemplateBinding Height}"
                               Fill="White" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--Outer menu items-->
    <Style TargetType="{x:Type MenuItem}">
        <Setter Property="Background"
                Value="#0f3c5a"></Setter>
        <Setter Property="Foreground"
                Value="White"></Setter>
        <Style.Triggers>
            <Trigger Property="IsHighlighted"
                     Value="True">
                <Setter Property="Background"
                        Value="Black"></Setter>
            </Trigger>
            <Trigger Property="IsEnabled"
                     Value="False">
                <Setter Property="Foreground"
                        Value="LightGray"></Setter>
            </Trigger>
        </Style.Triggers>
    </Style>

    <!-- Outer menu -->
    <Style TargetType="{x:Type ContextMenu}">
        <Setter Property="OverridesDefaultStyle"
                Value="True" />
        <Setter Property="SnapsToDevicePixels"
                Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContextMenu}">

                    <!--Here is where you change the border thickness to zero on the menu-->
                    <Border BorderThickness="0"
                            x:Name="Border"
                            Background="Transparent">
                        <StackPanel ClipToBounds="True"
                                    Orientation="Vertical"
                                    IsItemsHost="True" />
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver"
                                 Value="true">
                            <Setter TargetName="Border"
                                    Property="Background"
                                    Value="#0f3c5a" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- 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="#0f3c5a"
                        BorderThickness="1"
                        BorderBrush="#5082a4">
                    <Path Name="CheckMark"
                          Width="7"
                          Height="7"
                          Visibility="Hidden"
                          SnapsToDevicePixels="False"
                          Stroke="#5082a4"
                          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="#5082a4" />
            </Trigger>
            <Trigger Property="IsEnabled"
                     Value="false">
                <Setter Property="Foreground"
                        Value="#0f3c5a" />
            </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="#0f3c5a" />
                <Popup Name="Popup"
                       Placement="Right"
                       HorizontalOffset="-4"
                       IsOpen="{TemplateBinding IsSubmenuOpen}"
                       AllowsTransparency="True"
                       Focusable="False"
                       PopupAnimation="Fade">
                    <Border Name="SubmenuBorder"
                            SnapsToDevicePixels="True"
                            Background="#0f3c5a"
                            BorderBrush="#0f3c5a"
                            BorderThickness="1">
                        <StackPanel IsItemsHost="True"
                                    KeyboardNavigation.DirectionalNavigation="Cycle" />
                    </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="#5082a4" />
            </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="#0f3c5a" />
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
缱绻入梦 2024-09-19 17:11:36

你如何应用你的风格?

通常,如果您在“high”或“outer”元素的资源中定义样式,并且不给它任何键,则它将应用于下面目标类型的所有项目。

您是否在执行此操作并看到意外行为,或者您是否尝试在每个级别内嵌定义/应用样式?

编辑 1

查看您的 XAML,我认为问题在于您正在设计 ContextMenu 样式,但下面的菜单是 Menu 类型。我尝试的第一件事是将 StyleTargetType 属性更改为 Menu。看看这是否适用于所有级别。如果没有,我会将其改回来并添加另一个针对 MenuStyle 并查看该样式是否应用于子菜单。

编辑2

好吧,我想我已经得到你的答案了。子菜单实际上是一个 MenuItem,这在查看 XAML 而不是结果时是显而易见的。您在 ContextMenu 上设置的模板和样式也必须在作为子菜单的任何 MenuItem 上设置。我尝试了一下,并创建了一个以 MenuItem 为目标的样式,带有控件模板和 IsMouseOver 触发器,它似乎可以完成您正在尝试的操作。

How are you applying your styles?

Typically, if you define as style in a "high" or "outer" element's Resources, and give it no key, it will apply to all items of the target type below.

Are you doing this and seeing unexpected behaviour, or are you attempting to define/apply styles in-line at each level?

edit 1

Looking at your XAML, I think the issue is that you are styling ContextMenu, but menus below that are of type Menu. The first thing I'd try is to just change the TargetType attribute for the Style to Menu. See if that gets applied at all levels. If not, I'd change it back and add another Style targeting Menu and see if that one gets applied to the submenu.

edit 2

Okay, I think I've got your answer. The submenu is actually a MenuItem, which is obvious when looking at the XAML instead of the result. The template and styling that you're setting on the ContextMenu must also be set on any MenuItem that is a submenu. I tried it out and created a style that targets MenuItem with a control template and trigger for IsMouseOver and it appeared to do what you're trying.

苯莒 2024-09-19 17:11:36

为了不重复模板,您最好创建一个同时包含 PART_Popup 和子菜单箭头的模板,但隐藏错误,直到您被 Role 为 SubmenuHeader 触发为止。

To not duplicate the templates, you're better off creating one with both PART_Popup and arrow for the submenu, but hide the error until you're triggered with Role being SubmenuHeader.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文