2009-04-10 83 views
9

我工作的一些XAML的WPF应用程序,我有一些麻烦它做我想做的。这是我的XAML的一个样本:WPF:嵌套的MenuItems在工具栏

<!-- 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> 

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

我希望菜单项将只是一个菜单之外的工作,但我试着做了直接的东西,以防万一。在菜单中包含这些MenuItems,而是给这个菜单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> 

这段代码对我不起作用。我必须点击'Special'才能显示子菜单。

回答

0

我能找到,甚至接近产生这种行为的唯一办法是创造一个包含其标题本身就是所谓的“特殊项目”,并含有正常的孩子另一个菜单项的单个菜单项溢出的菜单。它按预期工作,但看起来奇怪(这可以通过自定义模板来弥补),也似乎是一个巨大的黑客攻击。我能想到的唯一“正确”方法是制作自己的MenuItem类控件,它在弹出时弹出一个ContextMenu或Popup,因为我不认为自定义ControlTemplate可以更改默认行为一个菜单,以免需要点击顶层项目。

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”的行为,而不是处理click事件。我想更全面地理解这一点,所以我尝试评论触发器的这一部分,并添加一个事件处理函数,它在'PreviewMouseDown'事件中调用'DoNothing()'方法。事实证明,我错过了一些东西,我认为这与聚焦和/或菜单如何处理其项目集合有关。 'DoNothing()'(routedEventArgs.Handled = true)之后不允许事件传播似乎消除了单击“特殊项目”菜单项时出现的问题。但是,如果从菜单导航或添加了另一个菜单项并单击该项,则可以关闭悬停行为或打开和关闭悬停行为。

2

另一种解决方案是使用现有的模板和覆盖模板与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事件,所以它什么也不做,但我不知道它会如何工作。

+0

你知道,这正是我一开始想要做的。我在细读MSDN并找到了Role属性,但我不知道改变它的正确方法。然后我发现上面贴出的快速修复剪切和粘贴怪物,哈哈。我是新来的wpf。 我试过了代码,不幸的是,子菜单没有出现在鼠标悬停中。我会再调查一下。 – 2009-04-18 02:36:46