WPF:工具栏中的嵌套菜单项

发布于 2024-07-17 01:11:04 字数 1757 浏览 3 评论 0原文

我正在为 wpf 应用程序开发一些 XAML,但在让它执行我想要的操作时遇到一些问题。 下面是我的 XAML 示例:

<!-- Tool Bar Tray -->
<ToolBarTray Name="toolBarTray1" DockPanel.Dock="Top">
    <!-- File And Edit Tools -->
    <ToolBar Name="toolBar1" Band="1" BandIndex="1">
        <!-- Regular Items -->
        <Button>A</Button>
        <Button>B</Button>
        <!-- Overflow Menu For Special Items -->
        <MenuItem ToolBar.OverflowMode="Always" Header="Special Items">
            <MenuItem Header="C"/>
            <MenuItem Header="D"/>
        </MenuItem>
    </ToolBar>
</ToolBarTray>

当我单击工具栏的溢出按钮时,会出现“特殊项目”菜单项,旁边有一个小箭头,指示嵌套元素。 但是,当我将鼠标悬停在“特殊项目”上或尝试单击它时,菜单项“C”和“D”不会显示。

我希望 MenuItem 能够在菜单之外工作,但为了以防万一,我尝试做直接的事情。 将这些 MenuItem 包含在菜单中,并为该菜单赋予 ToolBar.OverflowMode="Always" 属性会产生一些不需要的样式。 箭头不再存在,需要单击“特殊项目”条目才能激活子菜单,并且子菜单位置看起来有点偏离。

有谁知道发生了什么事吗?

编辑:将菜单添加到溢出中所产生的正是我所要求的(大惊喜)。 我所追求的是一种将顶级标题和项目转换为子菜单级别的方法。 我已转向 MSDN 上的此控件模板示例寻求解决方案(如下)。

编辑,编辑: @gcores(评论讨论):真的吗? 我错过了什么吗?

<ToolBar Name="toolBar1" Band="1" BandIndex="4"> 
    <!-- Displayed Buttons -->
    <Button>A</Button>
    <Button>B</Button>
    <!-- Special Items Menu -->
    <Menu ToolBar.OverflowMode="Always" >
        <MenuItem Style="{StaticResource MenuItemStyle}" Header="Special">
            <MenuItem Header="C"/>
            <MenuItem Header="D"/>
        </MenuItem>
    </Menu>
</ToolBar>

这个片段对我不起作用。 我必须单击“特殊”才能显示子菜单。

I am working on some XAML for a wpf application and I am having some trouble getting it to do what I want. Here is a sample of my XAML:

<!-- Tool Bar Tray -->
<ToolBarTray Name="toolBarTray1" DockPanel.Dock="Top">
    <!-- File And Edit Tools -->
    <ToolBar Name="toolBar1" Band="1" BandIndex="1">
        <!-- Regular Items -->
        <Button>A</Button>
        <Button>B</Button>
        <!-- Overflow Menu For Special Items -->
        <MenuItem ToolBar.OverflowMode="Always" Header="Special Items">
            <MenuItem Header="C"/>
            <MenuItem Header="D"/>
        </MenuItem>
    </ToolBar>
</ToolBarTray>

When I click on the overflow button of my toolbar, the "Special Items" MenuItem appears with a little arrow next to it, indicating nested elements. However, when I hover the mouse over "Special Items" or try to click on it, the MenuItems "C" and "D" are not being displayed.

I was hoping that MenuItem would just work outside of a Menu, but I tried to do the straight-forward thing, just in case. Including these MenuItems inside a Menu and, instead, giving this Menu the ToolBar.OverflowMode="Always" property produces some unwanted styling. The arrow is no longer present, the "Special Items" entry needs to be clicked on to activate the sub-menu and the sub-menu positioning looks a little off.

Does anyone know what is going on?

Edit: Adding a menu to the overflow is producing exactly what I requested (big surprise). What I am after is a way to convert top-level headers and items to the sub-menu level. I have turned towards this control template example on MSDN for a solution (below).

Edit,Edit:
@gcores (comment discussion): Really? Am I missing something?

<ToolBar Name="toolBar1" Band="1" BandIndex="4"> 
    <!-- Displayed Buttons -->
    <Button>A</Button>
    <Button>B</Button>
    <!-- Special Items Menu -->
    <Menu ToolBar.OverflowMode="Always" >
        <MenuItem Style="{StaticResource MenuItemStyle}" Header="Special">
            <MenuItem Header="C"/>
            <MenuItem Header="D"/>
        </MenuItem>
    </Menu>
</ToolBar>

This snippet doesn't work for me. I have to click on 'Special' for the sub-menu to display.

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

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

发布评论

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

评论(3

情绪操控生活 2024-07-24 01:11:04

另一种解决方案是使用现有模板并使用 SubmenuHeader 的模板覆盖 TopLevelHeader 的模板。

<Style x:Key="MenuItemStyle" TargetType="{x:Type MenuItem}">
  <Style.Triggers>
    <Trigger Property="Role" Value="TopLevelHeader">
      <Setter Property="Template"
              Value="{StaticResource {x:Static MenuItem.SubmenuHeaderTemplateKey}}"/>
    </Trigger>
  </Style.Triggers> 
</Style>

并在顶级 MenuItem 中使用此样式。 这应该会简化你的代码。

编辑
你是对的,它只有在你点击它时才起作用(不知道我是如何说服自己它起作用的,抱歉:))。
它的功能就像一个 TopLevelMenu,尽管模板另有说明,但它非常令人困惑。

我唯一能想到的是添加一个触发器来显示 IsMenuOver 上的子菜单并处理 Click 事件,因此它什么也不做,但我不知道这会工作得如何。

Another solution is to use the existing templates and override the Template for the TopLevelHeader with the Template of the SubmenuHeader.

<Style x:Key="MenuItemStyle" TargetType="{x:Type MenuItem}">
  <Style.Triggers>
    <Trigger Property="Role" Value="TopLevelHeader">
      <Setter Property="Template"
              Value="{StaticResource {x:Static MenuItem.SubmenuHeaderTemplateKey}}"/>
    </Trigger>
  </Style.Triggers> 
</Style>

And use this style in your top level MenuItem. That should simplify your code.

EDIT:
You're right, it only works when you click on it (don't know how I convinced myself it worked, sorry :)).
It's functionality is like a TopLevelMenu even though the Template says otherwise, its quite confusing.

Only thing I can think of is adding a Trigger to show the Submenu on IsMenuOver and handling the Click event so it does nothing but I don't know how well that would work.

删除会话 2024-07-24 01:11:04

经过更多阅读后,我正在使用的解决方案如下。

<!-- Resource Dictionary Stuff -->

<!-- Some Brushes -->
<SolidColorBrush x:Key="Brush_1"
    Color="White" />

<LinearGradientBrush x:Key="Brush_2"
    StartPoint="0 0"
    EndPoint="0 1">

    <GradientStop
        Color="White"
        Offset="0"/>

    <GradientStop 
        Color="DarkSeaGreen"
        Offset="1"/>

</LinearGradientBrush>

<SolidColorBrush x:Key="Brush_3"
    Color="DarkOliveGreen"/>

<!-- Custom MenuItem - Top Level Header - Style 1 -->
<Style x:Key="MenuItem_TLH_Style1"
    TargetType="MenuItem">

    <!--<EventSetter Event="PreviewMouseDown" Handler="DoNothing"/>-->

    <Setter Property="Template">
        <Setter.Value>

            <ControlTemplate x:Name="ControlTemplate"
                TargetType="MenuItem">

                <!-- A headered text that may display a submenu
                     on a trigger. This submenu is the host for a
                     menu item's items. -->
                <Border x:Name="BoundaryBorder"
                    Background="{StaticResource Brush_1}"
                    BorderThickness="1">

                    <Grid x:Name="ContainerGrid">

                        <ContentPresenter x:Name="HeaderContent"
                            Margin="6 3 6 3" 
                            ContentSource="Header"
                            RecognizesAccessKey="True"/>

                        <Popup x:Name="SubmenuPopup"
                            Placement="Bottom"
                            IsOpen="{TemplateBinding IsSubmenuOpen}"
                            AllowsTransparency="True"
                            Focusable="False"
                            PopupAnimation="Fade">

                            <Border x:Name="SubmenuBoundaryBorder"
                                SnapsToDevicePixels="True"
                                Background="{StaticResource Brush_1}"
                                BorderBrush="{StaticResource SolidBorderBrush}"
                                BorderThickness="1">

                                <StackPanel x:Name="ItemsStackPanel"
                                    IsItemsHost="True"
                                    KeyboardNavigation.DirectionalNavigation="Cycle"/>

                            </Border>
                        </Popup>
                    </Grid>
                </Border>

                <ControlTemplate.Triggers>

                    <!--  -->
                    <Trigger
                        Property="IsSuspendingPopupAnimation"
                        Value="true">

                        <Setter 
                            TargetName="SubmenuPopup"
                            Property="PopupAnimation"
                            Value="Fade"/>

                    </Trigger>

                    <!-- On mouse-over, show the submenu and highlight the header. -->
                    <Trigger 
                        Property="IsMouseOver"
                        Value="true">

                        <Setter 
                            TargetName="BoundaryBorder"
                            Property="Background"
                            Value="{StaticResource Brush_2}"/>

                        <Setter 
                            TargetName="BoundaryBorder"
                            Property="BorderBrush"
                            Value="{StaticResource Brush_3}"/>

                        <Setter
                            Property="IsSubmenuOpen"
                            Value="true"/>

                        <!-- sloppy? -->
                        <Setter
                            TargetName="SubmenuPopup"
                            Property="IsOpen"
                            Value="true"/>

                    </Trigger>

                    <Trigger 
                        SourceName="SubmenuPopup"
                        Property="AllowsTransparency"
                        Value="true">

                        <Setter 
                            TargetName="SubmenuBoundaryBorder"
                            Property="CornerRadius"
                            Value="0 0 4 4"/>

                        <Setter 
                            TargetName="SubmenuBoundaryBorder"
                            Property="Padding"
                            Value="0 0 0 3"/>

                    </Trigger>

                    <!-- Visually indicate an unaccessible menu item. -->
                    <Trigger
                        Property="IsEnabled"
                        Value="false">

                        <Setter 
                            Property="Foreground"
                            Value="{StaticResource DisabledForegroundBrush}"/>

                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<!-- ... -->

<!-- Inside a window XAML file -->

<!-- Tool Bar Tray -->
<ToolBarTray x:Name="toolBarTray1"
    DockPanel.Dock="Top">

    <!-- File And Edit Tools -->
    <ToolBar x:Name="toolBar1" 
        Band="1" BandIndex="1">

        <!-- Displayed Buttons -->
        <Button x:Name="ButtonA"
            Content="A"/>

        <Button x:Name="ButtonB"
            Content="B"/>

        <!-- Overflow Menu For Special Items -->
        <Menu x:Name="OverflowMenu"
            ToolBar.OverflowMode="Always">

            <MenuItem x:Name="SpecialsMenuItem" 
                Style="{StaticResource MyStyle}"
                Header="Special Items">

                <MenuItem x:Name="CMenuItem"
                    Header="C">

                    <MenuItem x:Name="DMenuItem"
                        Header="D"/>

                </MenuItem>
            </MenuItem>
        </Menu>
    </ToolBar>
</ToolBarTray>

我攻击鼠标悬停时“SubmenuPopup”的行为,而不是处理单击事件。 我想更全面地理解这一点,因此我尝试注释掉触发器的这一部分,并添加一个事件处理程序,该事件处理程序在“PreviewMouseDown”事件上调用“DoNothing()”方法。 事实证明,我错过了一些东西,我认为这与焦点和/或菜单如何处理其项目集合有关。 不允许事件在“DoNothing()”之后传播(routedEventArgs.Handled = true)似乎可以消除单击“特殊项目”菜单项时出现的问题。 但是,如果用户离开菜单或添加另一个菜单项,然后单击该菜单项,则可以关闭或打开和关闭悬停行为。

After more reading, a solution I am using is below.

<!-- Resource Dictionary Stuff -->

<!-- Some Brushes -->
<SolidColorBrush x:Key="Brush_1"
    Color="White" />

<LinearGradientBrush x:Key="Brush_2"
    StartPoint="0 0"
    EndPoint="0 1">

    <GradientStop
        Color="White"
        Offset="0"/>

    <GradientStop 
        Color="DarkSeaGreen"
        Offset="1"/>

</LinearGradientBrush>

<SolidColorBrush x:Key="Brush_3"
    Color="DarkOliveGreen"/>

<!-- Custom MenuItem - Top Level Header - Style 1 -->
<Style x:Key="MenuItem_TLH_Style1"
    TargetType="MenuItem">

    <!--<EventSetter Event="PreviewMouseDown" Handler="DoNothing"/>-->

    <Setter Property="Template">
        <Setter.Value>

            <ControlTemplate x:Name="ControlTemplate"
                TargetType="MenuItem">

                <!-- A headered text that may display a submenu
                     on a trigger. This submenu is the host for a
                     menu item's items. -->
                <Border x:Name="BoundaryBorder"
                    Background="{StaticResource Brush_1}"
                    BorderThickness="1">

                    <Grid x:Name="ContainerGrid">

                        <ContentPresenter x:Name="HeaderContent"
                            Margin="6 3 6 3" 
                            ContentSource="Header"
                            RecognizesAccessKey="True"/>

                        <Popup x:Name="SubmenuPopup"
                            Placement="Bottom"
                            IsOpen="{TemplateBinding IsSubmenuOpen}"
                            AllowsTransparency="True"
                            Focusable="False"
                            PopupAnimation="Fade">

                            <Border x:Name="SubmenuBoundaryBorder"
                                SnapsToDevicePixels="True"
                                Background="{StaticResource Brush_1}"
                                BorderBrush="{StaticResource SolidBorderBrush}"
                                BorderThickness="1">

                                <StackPanel x:Name="ItemsStackPanel"
                                    IsItemsHost="True"
                                    KeyboardNavigation.DirectionalNavigation="Cycle"/>

                            </Border>
                        </Popup>
                    </Grid>
                </Border>

                <ControlTemplate.Triggers>

                    <!--  -->
                    <Trigger
                        Property="IsSuspendingPopupAnimation"
                        Value="true">

                        <Setter 
                            TargetName="SubmenuPopup"
                            Property="PopupAnimation"
                            Value="Fade"/>

                    </Trigger>

                    <!-- On mouse-over, show the submenu and highlight the header. -->
                    <Trigger 
                        Property="IsMouseOver"
                        Value="true">

                        <Setter 
                            TargetName="BoundaryBorder"
                            Property="Background"
                            Value="{StaticResource Brush_2}"/>

                        <Setter 
                            TargetName="BoundaryBorder"
                            Property="BorderBrush"
                            Value="{StaticResource Brush_3}"/>

                        <Setter
                            Property="IsSubmenuOpen"
                            Value="true"/>

                        <!-- sloppy? -->
                        <Setter
                            TargetName="SubmenuPopup"
                            Property="IsOpen"
                            Value="true"/>

                    </Trigger>

                    <Trigger 
                        SourceName="SubmenuPopup"
                        Property="AllowsTransparency"
                        Value="true">

                        <Setter 
                            TargetName="SubmenuBoundaryBorder"
                            Property="CornerRadius"
                            Value="0 0 4 4"/>

                        <Setter 
                            TargetName="SubmenuBoundaryBorder"
                            Property="Padding"
                            Value="0 0 0 3"/>

                    </Trigger>

                    <!-- Visually indicate an unaccessible menu item. -->
                    <Trigger
                        Property="IsEnabled"
                        Value="false">

                        <Setter 
                            Property="Foreground"
                            Value="{StaticResource DisabledForegroundBrush}"/>

                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<!-- ... -->

<!-- Inside a window XAML file -->

<!-- Tool Bar Tray -->
<ToolBarTray x:Name="toolBarTray1"
    DockPanel.Dock="Top">

    <!-- File And Edit Tools -->
    <ToolBar x:Name="toolBar1" 
        Band="1" BandIndex="1">

        <!-- Displayed Buttons -->
        <Button x:Name="ButtonA"
            Content="A"/>

        <Button x:Name="ButtonB"
            Content="B"/>

        <!-- Overflow Menu For Special Items -->
        <Menu x:Name="OverflowMenu"
            ToolBar.OverflowMode="Always">

            <MenuItem x:Name="SpecialsMenuItem" 
                Style="{StaticResource MyStyle}"
                Header="Special Items">

                <MenuItem x:Name="CMenuItem"
                    Header="C">

                    <MenuItem x:Name="DMenuItem"
                        Header="D"/>

                </MenuItem>
            </MenuItem>
        </Menu>
    </ToolBar>
</ToolBarTray>

I attack the behavior of 'SubmenuPopup' on a mouse-over, rather than handling the click event. I'd like to understand this more fully, so I tried commenting out this part of the trigger and adding an event handler that calls a 'DoNothing()' method on the 'PreviewMouseDown' event. It turns out that I am missing something and I think it is related to focusing and/or how a menu handles its items collection. Not allowing an event to propagate after 'DoNothing()' (routedEventArgs.Handled = true) seems to eliminate the problems when clicking on the "Special Items" menu item. However, if one navigated away from the menu or added another menu item and then clicked on that, the hover behavior can be turned off or switched on and off.

心凉怎暖 2024-07-24 01:11:04

我发现接近生成这种行为的唯一方法是在溢出中创建一个菜单,其中包含一个菜单项,其标题本身就是另一个名为“特殊项目”的菜单项并包含正确的子项。 它按预期工作,但看起来很奇怪(这可以通过自定义模板来补救),而且看起来像是一个巨大的黑客攻击。 我能想到的唯一“正确”的方法是制作您自己的类似 MenuItem 的控件,该控件在悬停时会弹出 ContextMenu 或 Popup,因为我不认为自定义 ControlTemplate 可以更改的默认行为菜单,以便不需要单击顶级项目。

The only way I could find to even come close to generating this behaviour was to create a menu in the overflow which contained a single menu item whose header was itself another menu item called "Special Items" and containing the proper children. It worked as intended but looked bizarre (this could be remedied by custom templates) and also seems like a huge hack. The only "proper" way to do this that I can think of would be making your own MenuItem-like control which pops up a ContextMenu or Popup when hovered upon, since I don't think that a custom ControlTemplate can change the default behaviour of a menu so as not to require a click on the top level item.

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