2009-04-10 10 views
9

Sto lavorando ad alcuni XAML per un'applicazione wpf e sto avendo qualche problema a farlo fare ciò che voglio. Ecco un esempio del mio XAML:WPF: MenuItem nidificati in una barra degli strumenti

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

Quando clicco sul pulsante di overflow della mia barra degli strumenti, gli "Elementi speciali" MenuItem appare con una piccola freccia accanto ad esso, indicando gli elementi annidati. Tuttavia, quando si passa il mouse su "Oggetti speciali" o si tenta di fare clic su di esso, i MenuItem "C" e "D" non vengono visualizzati.

Speravo che MenuItem funzionasse solo al di fuori di un Menu, ma ho cercato di fare la cosa semplice, per ogni evenienza. Includendo questi MenuItem all'interno di un Menu e, invece, dando a questo Menu la proprietà ToolBar.OverflowMode = "Always" produce uno stile indesiderato. La freccia non è più presente, è necessario fare clic sulla voce "Elementi speciali" per attivare il sottomenu e il posizionamento del sottomenu appare leggermente disattivato.

Qualcuno sa cosa sta succedendo?

Modifica: l'aggiunta di un menu all'overflow produce esattamente ciò che ho richiesto (grande sorpresa). Quello che sto cercando è un modo per convertire intestazioni e voci di livello superiore a livello di sottomenu. Mi sono rivolto a questo esempio di modello di controllo su MSDN per una soluzione (sotto).

Modifica, Modifica: @gcores (discussione di commenti): Davvero? Mi sto perdendo qualcosa?

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

Questo snippet non funziona per me. Devo fare clic su "Speciale" per visualizzare il sottomenu.

risposta

0

L'unico modo che potevo trovare per avvicinarsi a generare questo comportamento era di creare un menu nell'overflow che conteneva una singola voce di menu la cui intestazione era essa stessa un'altra voce di menu chiamata "Elementi speciali" e contenente i figli appropriati. Ha funzionato come previsto ma è sembrato bizzarro (questo potrebbe essere risolto da modelli personalizzati) e sembra anche un enorme hack. L'unico modo "corretto" per farlo è quello di creare il tuo controllo MenuItem che fa apparire un ContextMenu o Popup quando ci si sofferma sopra, dal momento che non penso che un ControlTemplate personalizzato possa modificare il comportamento predefinito di un menu in modo da non richiedere un clic sull'elemento di livello superiore.

1

Dopo ulteriori letture, una soluzione che sto usando è sotto.

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

Mi attacco il comportamento di 'SubmenuPopup' su un mouse-over, piuttosto che la gestione dell'evento click. Mi piacerebbe capire questo più pienamente, così ho provato a commentare questa parte del trigger e aggiungere un gestore di eventi che chiama un metodo "DoNothing()" nell'evento "PreviewMouseDown". Si scopre che mi manca qualcosa e penso che sia legato alla messa a fuoco e/o al modo in cui un menu gestisce la sua collezione di oggetti. Non consentire la propagazione di un evento dopo "DoNothing()" (routedEventArgs.Handled = true) sembra eliminare i problemi quando si fa clic sulla voce di menu "Articoli speciali". Tuttavia, se uno si è allontanato dal menu o ha aggiunto un'altra voce di menu e ha fatto clic su di esso, il comportamento al passaggio del mouse può essere disattivato o attivato e disattivato.

2

Un'altra soluzione consiste nell'utilizzare i modelli esistenti e sovrascrivere il modello per TopLevelHeader con il modello del sottomenuHeader.

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

E utilizzare questo stile nel menu di livello superiore MenuItem. Questo dovrebbe semplificare il tuo codice.

EDIT: Hai ragione, funziona solo quando si fa clic su di esso (non so come mi convinsi che ha funzionato, mi dispiace :)). La funzionalità è come un TopLevelMenu anche se il modello dice diversamente, è piuttosto confuso.

L'unica cosa che posso pensare è aggiungere un trigger per mostrare il sottomenu su IsMenuOver e gestire l'evento Click in modo che non faccia nulla, ma non so quanto bene funzionerebbe.

+0

Sapete, questo è esattamente quello che stavo cercando di fare in un primo momento. Stavo controllando MSDN e ho trovato la proprietà Role, ma non conoscevo il modo corretto per cambiarlo. Ho poi trovato quella dimostrazione di taglia e incolla a correzione rapida che ho postato sopra, lol. Sono nuovo di wpf. Ho provato il codice e, sfortunatamente, il sottomenu non appare al passaggio del mouse. Lo esaminerò un po 'di più. –

+0

Oh, avvolgi il tuo MenuItem in un Menu. Altrimenti non c'è funzionalità. L'ho provato e funziona. – gcores

+0

Vedere "Modifica, modifica" in OP. –