wpf contextmenu 点击打开子菜单

wpf contextmenu open submenu on click

我在 WPF 中有一个包含多个子菜单的上下文菜单。默认行为是,如果您将鼠标悬停在其下方有项目的菜单项上,它将打开子菜单。但是,我想更改它,使其不会在悬停时打开,而是在左键单击时打开。

我复制了 MenuItem 的默认模板。在此,我做了一些修改:

<ControlTemplate x:Key="{ComponentResourceKey ResourceId=SubmenuHeaderTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}" TargetType="{x:Type MenuItem}">
    <!-- some default template code -->
    <ControlTemplate.Triggers>
        <Trigger Property="IsSuspendingPopupAnimation" Value="true">
            <Setter Property="PopupAnimation" TargetName="PART_Popup" Value="None"/>
        </Trigger>
        <Trigger Property="Icon" Value="{x:Null}">
            <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
        </Trigger>
        <Trigger Property="IsChecked" Value="True">
            <Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
            <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
        </Trigger>
        <Trigger Property="IsHighlighted" Value="True">
            <Setter Property="Background" TargetName="templateRoot" Value="Transparent"/>
            <Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource MenuItem.Highlight.Border}"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="False">
            <Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{StaticResource Menu.Disabled.Foreground}"/>
            <Setter Property="Fill" TargetName="Glyph" Value="{StaticResource Menu.Disabled.Foreground}"/>
            <Setter Property="Fill" TargetName="RightArrow" Value="{StaticResource Menu.Disabled.Foreground}"/>
        </Trigger>
        <Trigger Property="ScrollViewer.CanContentScroll" SourceName="SubMenuScrollViewer" Value="false">
            <Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=SubMenuScrollViewer}"/>
            <Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=SubMenuScrollViewer}"/>
        </Trigger>

        <!-- my code to supress the opening of the submenu in mouseover -->
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="IsOpen" TargetName="PART_Popup" Value="False"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

起初这似乎奏效了。但是,当我将鼠标慢慢移动到另一个 menuItem 时,它会出现片刻 - 可能 space 'IsMouseOver' 不正确,但子菜单仍然显示。

我怎样才能完全禁止它 - 除非有人点击 menuItem?

此行为是由 TemplateBinding IsSubmenuOpen 引起的,它会在触发器将其设置回 False 之前自动将 IsOpen 设置为 True。

<Popup 
    Name="PART_Popup"
    Placement="Right"
    HorizontalOffset="-4" 
    IsOpen="{TemplateBinding IsSubmenuOpen}"
    AllowsTransparency="True" 
    Focusable="False"
    PopupAnimation="Fade">
    <Border 
        ...
    </Border>
</Popup>

由于您已经使用点击事件连接了东西,您只需设置

IsOpen="False"

另一种解决方法是设置

IsOpen="{TemplateBinding IsChecked}"

并在每次单击 MenuItem 时设置 IsChecked 属性。