2010-11-16 4 views
10

J'ai un menu contextuel qui obtient les éléments de menu par liaison de données (j'utilise le modèle MVVM):WPF: Hiding ContextMenu à vide

<ContextMenu ItemsSource="{Binding Path=ContextMenuItems}" /> 

Cela fonctionne très bien. Cependant, dans les cas où il n'y a pas d'éléments de menu à afficher, je ne veux pas que le menu contextuel apparaisse du tout. Y a-t-il un moyen d'accomplir cela? Une sorte de déclencheur XAML peut-être?

J'ai essayé d'attraper l'événement Ouvert et de fermer le menu contextuel lorsqu'il n'y a pas d'enfants. Cela fonctionne mais le menu contextuel continue de clignoter ...

Répondre

14

Peut-être que vous lierez à la propriété de comptage de vos éléments de menu et utilisez un convertisseur pour définir la visibilité du menu contextuel.

<ContextMenu ItemsSource="{Binding Path=ContextMenuItems}" 
       Visibility="{Binding Path=ContextMenuItems.Count,Converter={StaticResource zeroToHiddenConverter}}"> 

public class ZeroToHiddenConverter:IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     int count = (int) value; 

     if (count == 0) 
     { 
      return Visibility.Hidden; 
     } 
     else 
     { 
      return Visibility.Visible; 
     } 
    } 
+0

Bonne réponse! J'ai essayé de déclencher HasItems et de définir la visibilité sur false, mais j'ai ensuite obtenu un menu contextuel clignotant pendant une fraction de seconde lors de l'ajout de menuitems, mais si ce n'est pas le cas ici, c'est définitivement la façon de le faire. –

+0

Content de l'entendre. Veuillez marquer ceci comme réponse si rien d'autre n'a besoin d'être ajouté. – ThomasAndersson

+0

Fonctionne bien! Merci Tendlon! :) – haagel

0

Vous pouvez essayer de faire une fixation sur la visibilité sur Items.Count avec un convertisseur de valeur - qui devrait empêcher votre menu d'apparaître :)

0

Si vous utilisez la solution de Tendlon sur une Contrôle TreeView (et probablement tout contrôle de type liste) avec un menu contextuel, il a des problèmes.

  1. Faites un clic droit sur un nœud avec non Menu contextuel Articles => Rien ne se passe (ce qui est bon)
  2. Clic gauche sur un nœud avec le menu contextuel Articles => Le menu contextuel apparaît (ce qui est mauvais)
3

Voici comment vous pouvez définir un style large d'application pour masquer des menus contextuels vides. HasItems est une propriété de dépendance sur le ContextMenu lui-même, de sorte que vous pouvez définir la visibilité du menu contextuel basé sur ce booléen.

Voici comment le faire dans un dictionnaire de ressources:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 

    <BooleanToVisibilityConverter x:Key="VisibilityOfBool" /> 

    <Style TargetType="{x:Type ContextMenu}"> 
     <Setter Property="Visibility" Value="{Binding HasItems, RelativeSource={RelativeSource Self}, Converter={StaticResource VisibilityOfBool}}"/> 
    </Style> 
</ResourceDictionary> 
19

Vous pouvez définir un style implicite:

<Style TargetType="{x:Type ContextMenu}"> 
    <Style.Triggers> 
     <Trigger Property="HasItems" Value="False"> 
      <Setter Property="Visibility" Value="Collapsed" /> 
     </Trigger> 
    </Style.Triggers> 
</Style> 

Cela devrait fonctionner pour tous vos menus contextuels à la fois.

+2

Fonctionne pour moi. Très similaire à la réponse d'Adam (mise à jour aussi), mais j'aime mieux le Trigger que le BooleanToVisibilityConverter. Et clairement mieux que la réponse acceptée - je n'ai pas connu le menu contextuel clignotant Meleak mentionné. –

+1

Mieux que l'option Convertisseur. Le problème qui reste est que la propriété HasItems est également vraie lorsque les éléments (MenuItems) sont invisibles. Il n'y a pas de propriété HasVisibleItems: - / – mamuesstack

0

Je suis venu avec une solution pour un TreeView qui utilise le rappel OnContextMenuOpening. Cela évite le problème mentionné par Alex G. Si vous réduisez le menu avec un style XAML, il n'apparaît pas lorsque le menu contextuel est vide, mais il apparaît ensuite lorsque vous cliquez avec le bouton gauche sur un autre élément.

Le code recherche le TreeViewItem qui veut ouvrir le ContextMenu, et s'il ne contient aucun élément, il définit la propriété Handled de l'événement sur true.

protected override void OnContextMenuOpening(ContextMenuEventArgs e) { 
    var item = FindTreeViewItem(e.OriginalSource as DependencyObject); 
    var contextMenu = item.ContextMenu; 
    if (contextMenu != null && !contextMenu.HasItems) { 
     e.Handled = true; 
    } 
} 

private TreeViewItem FindTreeViewItem(DependencyObject dependencyObject) { 
    if (dependencyObject == null) { 
     return null; 
    } 
    var treeViewItem = dependencyObject as TreeViewItem; 
    if (treeViewItem != null) { 
     return treeViewItem; 
    } 
    return FindTreeViewItem(VisualTreeHelper.GetParent(dependencyObject)); 
}