如何隐藏ContextMenus没有可见的项目?

时间:2015-02-03 16:13:15

标签: c# wpf contextmenu

我有几个ContextMenus,其项目定义如下:

<ContextMenu>
    <MenuItem Header="Item 1" Command="{Binding Item1Command}"/>
    <MenuItem Header="Item 2" Command="{Binding Item2Command}"/>
    <MenuItem Header="Item 3" Command="{Binding Item3Command}"/>
</ContextMenu>

Command绑定设置了CanExecute,因此当它为假时,MenuItemIsEnabled=false。这会继续触发,在Visibility=Collapsed时设置IsEnabled=false,同样也会发生相反的情况。我遇到的问题是如果所有MenuItem都被禁用,ContextMenu仍会显示为一个小的空白矩形。我有很多ContextMenu,那么实现这个的最模块化方法是什么?

3 个答案:

答案 0 :(得分:0)

我最终做了一个不同的解决方法,而不是隐藏ContextMenu的可见性。它似乎效率较低,因为它检查所有FrameworkElement ContextMenus,但它正在工作:

EventManager.RegisterClassHandler(typeof(FrameworkElement), ContextMenuOpeningEvent,
    new RoutedEventHandler(OnContextMenuOpening));

private void OnContextMenuOpening(object sender, RoutedEventArgs e)
{
    var control = (sender as FrameworkElement);
    var menu = control == null ? null : control.ContextMenu;
    if (menu != null)
    {
        var items = menu.Items.Cast<MenuItem>();
        if (items.All(i => i.Visibility != Visibility.Visible))
        {
            e.Handled = true;
        }
    }
}

如果有更好的方法可以在没有代码的情况下做到这一点,那么对于父控件来说,我仍然愿意接受其他解决方案。

答案 1 :(得分:0)

这是一段xaml,它将让你开始使用&#34; Conditional&#34;文本菜单。
请注意:这只是起点

<ListView>
         <ListView.Resources>
             <ContextMenu x:Key="initial">
                 <Menu>
                     <MenuItem Header="First Option"></MenuItem>
                 </Menu>
             </ContextMenu>
             <Style TargetType="ListViewItem">
                 <Style.Triggers>
                     <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="1">
                         <Setter Property="ContextMenu" Value="{StaticResource initial}" />
                     </DataTrigger>
                 </Style.Triggers>
                 <Setter Property="ContextMenu" Value="{StaticResource initial}"/>
             </Style>
         </ListView.Resources>
         <ListViewItem>1</ListViewItem>
         <ListViewItem>2</ListViewItem>
     </ListView>

答案 2 :(得分:0)

我发现解决此问题的唯一方法是通过附加属性,但它对我来说似乎可以接受。首先定义一个具有属性的类:

public class ContextMenuExtension
{
    public static bool GetHideOnEmpty(DependencyObject obj)
    {
        return (bool)obj.GetValue(HideOnEmptyProperty);
    }

    public static void SetHideOnEmpty(DependencyObject obj, bool value)
    {
        obj.SetValue(HideOnEmptyProperty, value);
    }

    public static readonly DependencyProperty HideOnEmptyProperty =
        DependencyProperty.RegisterAttached("HideOnEmpty", typeof(bool), typeof(ContextMenuExtension), new UIPropertyMetadata(false, HideOnEmptyChanged));

    private static void HideOnEmptyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var contextMenu = d as ContextMenu;

        if (contextMenu == null)
            return;

        contextMenu.Loaded += ContextMenu_Loaded;
    }

    private static void ContextMenu_Loaded(object sender, RoutedEventArgs e)
    {
        var contextMenu = sender as ContextMenu;
        var hideOnEmpty = GetHideOnEmpty(contextMenu);

        HideContextMenu(contextMenu, hideOnEmpty);
    }

    //This is where we check if all the items are not visible
    private static void HideContextMenu(ContextMenu contextMenu, bool val)
    {
        //First, we have to know if the HideOnEmpty property is set to true. 
        if (val)
        {
            //Check if the contextMenu is either null or empty
            if (contextMenu.Items == null || contextMenu.Items.Count < 1)
                contextMenu.Visibility = Visibility.Collapsed; //Hide the contextMenu
            else
            {
                bool hide = true;
                //Check if all the items are not visible.  
                foreach (MenuItem i in contextMenu.Items)
                {
                    if (i.Visibility == Visibility.Visible)
                    {
                        hide = false;
                        break;
                    }
                }

                //If one or more items above is visible we won't hide the contextMenu.
                if (!hide)
                    contextMenu.Visibility = Visibility.Visible;
                else
                    contextMenu.Visibility = Visibility.Collapsed;
            }
        }
    }
}

然后在XAML中使用ContextMenu在上面的类中添加一个名称空间,然后执行以下操作:

<ContextMenu cc:ContextMenuExtension.HideOnEmpty="True">
   <MenuItem Header="Delete" Command="<delete_command>" Visibility="Collapsed"/>
</ContextMenu>

每次用户右键单击以查看菜单时,它将触发“ ContextMenuExtension”类中的“ HideContextMenu”方法,如果没有任何项或所有项都不可见-隐藏整个ContextMenu。