WPF: Hiding ContextMenu when empty

天涯浪子 提交于 2019-12-05 01:10:02
ThomasAndersson

Maybe bind to your menu items collections count property and use a converter to set the context menu's visibility.

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

You can define an implicit style:

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

This should work for all your context menus at once.

Below is how you can set an application wide style for hiding empty context menus.

HasItems is a dependency property on the ContextMenu itself, so you can set the context menu's visibility based on that boolean.

Here is how to do it in a resource dictionary:

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

If you use Tendlon's solution on a TreeView control (and probably any list type control) with a context menu, it has problems.

  1. Right click on a node with not Context Menu Items => Nothing happens (which is good)
  2. Left click on a node with Context Menu Items => The context menu appears (which is bad)

You could try making a binding on Visibility on Items.Count with a value converter - that should prevent your menu from appearing :)

I came up with a solution for a TreeView that uses the OnContextMenuOpening callback. It prevents the problem Alex G mentioned. If you collapse the menu with a XAML style then it does not appear when the contextmenu is empty, however it appears afterwards when you left-click on another item.

The code looks for the TreeViewItem which wants to open the ContextMenu, and if it has no items, it sets the Handled property of the event to 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));
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!