【问题标题】:WPF: Hiding ContextMenu when emptyWPF:为空时隐藏 ContextMenu
【发布时间】:2010-11-16 09:13:20
【问题描述】:

我有一个通过数据绑定获取菜单项的上下文菜单(我使用的是 MVVM 模式):

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

这很好用。但是,在没有要显示的菜单项的情况下,我根本不希望显示上下文菜单。有没有办法做到这一点?可能是某种 XAML 触发器?

我尝试捕捉 Opened 事件,当没有子项时关闭上下文菜单。这可行,但上下文菜单仍然闪烁...

【问题讨论】:

    标签: wpf mvvm contextmenu


    【解决方案1】:

    你可以定义一个隐式样式:

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

    这应该同时适用于所有上下文菜单。

    【讨论】:

    • 为我工作。与亚当的答案非常相似(也赞成),但我更喜欢触发器而不是 BooleanToVisibilityConverter。显然比公认的答案更好 - 我没有体验过 Meleak 提到的闪烁的上下文菜单。
    • 优于转换器选项。剩下的问题是当 Items (MenuItems) 不可见时,属性 HasItems 也是 true。没有 HasVisibleItems 属性:-/
    • 我试过你的方法,看起来很简单。但如果你有一个动态上下文菜单,如果不需要,里面的项目将被折叠,它就不起作用。关于如何解决这个问题的任何建议?
    【解决方案2】:

    也许绑定到您的菜单项集合计数属性并使用转换器来设置上下文菜单的可见性。

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

    【讨论】:

    • 好答案!我试图触发 HasItems 并将可见性设置为 false,但是当再次添加菜单项时,我得到了一个闪烁的上下文菜单,但如果这里不是这种情况,那么这绝对是这样做的方法。
    • 很高兴听到这个消息。如果不需要添加任何其他内容,请将其标记为已回答。
    • 工作正常!谢谢腾龙! :)
    • 这不是一个完整的解决方案。主要问题是当您的第一个上下文菜单中包含零项时,不会调用转换器。 'Count' 的初始属性值为 0,因此在计数发生变化之前不会调用转换器。
    • 当心!使用这种方法,ContextMenuItems 的 getter 将被调用 2 次。因此,如果您在 getter 中有任何逻辑,这将被计算两次。
    【解决方案3】:

    以下是如何设置应用程序范围的样式以隐藏空上下文菜单。

    HasItems 是 ContextMenu 本身的依赖属性,因此您可以根据该布尔值设置上下文菜单的可见性。

    这是在资源字典中的操作方法:

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

    【讨论】:

      【解决方案4】:

      如果您在带有上下文菜单的 TreeView 控件(可能还有任何列表类型的控件)上使用 Tendlon 的解决方案,则会出现问题。

      1. 右键单击没有上下文菜单项的节点 => 没有任何反应(这很好)
      2. 左键单击带有上下文菜单项的节点 => 出现上下文菜单(这很糟糕)

      【讨论】:

        【解决方案5】:

        我想出了一个使用 OnContextMenuOpening 回调的 TreeView 解决方案。它可以防止 Alex G 提到的问题。如果您使用 XAML 样式折叠菜单,那么当上下文菜单为空时它不会出现,但是当您左键单击另一个项目后它会出现。

        代码查找要打开 ContextMenu 的 TreeViewItem,如果没有项目,则将事件的 Handled 属性设置为 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));
        }
        

        【讨论】:

          【解决方案6】:

          您可以尝试使用值转换器对 Items.Count 的 Visibility 进行绑定 - 这应该会阻止您的菜单出现 :)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-01-05
            • 1970-01-01
            • 2017-12-09
            • 2015-08-05
            • 1970-01-01
            相关资源
            最近更新 更多