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

9

我正在为一个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”菜单项未显示。
我希望菜单项可以在菜单之外正常工作,但为了确保万无一失,我尝试了简单直接的方法。将这些菜单项包含在一个菜单中,并将此菜单赋予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>

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

3个回答

2

另一种解决方案是使用现有的模板,并用子菜单头的模板覆盖顶级标题的模板。

<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事件,使其无效,但我不知道这样做会有多好。


你知道吗,这正是我一开始尝试做的事情。我在浏览 MSDN 时找到了 Role 属性,但我不知道正确的更改方式。然后我发现了上面发布的快速修复剪切和粘贴怪物,哈哈。我很新手 WPF。我尝试了代码,但不幸的是,在鼠标悬停时子菜单没有出现。我会再调查一下的。 - Derek E
哦,将您的 MenuItem 包装在 Menu 中。否则没有功能。我已经尝试过并且有效。 - gcores

1

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

<!-- 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)似乎可以消除单击“Special Items”菜单项时出现的问题。但是,如果用户导航离开菜单或添加另一个菜单项,然后单击该菜单项,则悬停行为可能会关闭或打开。

0

我能找到的唯一接近生成此行为的方法是在溢出菜单中创建一个菜单,其中包含一个名为“特殊项目”的另一个菜单项,包含适当的子菜单。它按预期工作,但外观奇怪(可以通过自定义模板来解决),而且似乎是一个巨大的hack。我唯一想到的“正确”方法是创建自己的类似于MenuItem的控件,在悬停时弹出ContextMenu或Popup,因为我不认为自定义ControlTemplate可以更改菜单的默认行为,以便不需要点击顶级项。


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