2010-11-16 22 views
10

que tienen un menú contextual que recibe los elementos de menú a través de enlace de datos (estoy usando el patrón MVVM):WPF: Cómo ocultar ContextMenu cuando están vacíos

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

Esto funciona bien. Sin embargo, en los casos en que no hay elementos de menú para mostrar, no quiero que aparezca el menú contextual. ¿Hay alguna manera de lograr esto? Algún tipo de disparador XAML tal vez?

He intentado captar el evento Abierto o cerrar el menú contextual cuando no hay niños. Esto funciona pero el menú contextual aún parpadea por ...

Respuesta

14

Quizás se una a su propiedad de conteo de colecciones de elementos de menú y use un convertidor para establecer la visibilidad del menú contextual.

<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

¡Buena respuesta! Traté de activar HasItems y establecer la visibilidad en falso, pero luego recibí un menú contextual intermitente por una fracción de segundo al agregar elementos de menú nuevamente, pero si ese no es el caso aquí, esta es definitivamente la manera de hacerlo. –

+0

Me alegra oír eso. Marque esto como respondido si no se necesita agregar nada más. – ThomasAndersson

+0

¡Funciona bien! Gracias Tendlon! :) – haagel

0

Usted podría intentar hacer una unión en la visibilidad en Items.Count con un convertidor de valores - que se debe evitar que el menú aparezca :)

0

Si utiliza la solución de Tendlon en una Control TreeView (y probablemente cualquier control de tipo de lista) con un menú contextual, tiene problemas.

  1. haga clic en el botón derecho en un nodo con no elementos del menú contextual => no pasa nada (que es bueno)
  2. Izquierda haga clic en un nodo con elementos del menú contextual aparece => El menú contextual (que es malo)
3

A continuación se muestra cómo puede establecer un estilo de aplicación para ocultar los menús contextuales vacíos.

HasItems es una propiedad de dependencia en el ContextMenu mismo, por lo que puede establecer la visibilidad del menú contextual en función de ese booleano.

Aquí es cómo hacerlo en un diccionario de recursos:

<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

Se puede definir un estilo implícita:

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

Esto debería funcionar para todos los menús de contexto de una vez.

+2

Funciona para mí. Muy similar a la respuesta de Adam (upvoted también), pero me gusta el Trigger mejor que BooleanToVisibilityConverter. Y claramente mejor que la respuesta aceptada: no he experimentado el menú contextual intermitente que mencionó Meleak. –

+1

Mejor que la opción Convertidor. El problema que permanece es que la propiedad HasItems también es verdadera cuando Items (MenuItems) son invisibles. No hay propiedad HasVisibleItems: - / – mamuesstack

0

Se me ocurrió una solución para un TreeView que utiliza la devolución de llamada OnContextMenuOpening. Evita el problema que Alex G mencionó. Si contrae el menú con un estilo XAML, no aparece cuando el menú contextual está vacío; sin embargo, aparece después cuando hace clic con el botón izquierdo en otro elemento.

El código busca el TreeViewItem que desea abrir el ContextMenu, y si no tiene elementos, establece la propiedad Handled del evento en verdadero.

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)); 
} 
Cuestiones relacionadas