C# 如何隐藏没有可见项的上下文菜单?
我有几个上下文菜单,其中的项目定义如下:C# 如何隐藏没有可见项的上下文菜单?,c#,wpf,contextmenu,C#,Wpf,Contextmenu,我有几个上下文菜单,其中的项目定义如下: <ContextMenu> <MenuItem Header="Item 1" Command="{Binding Item1Command}"/> <MenuItem Header="Item 2" Command="{Binding Item2Command}"/> <MenuItem Header="Item 3" Command="{Binding Item3Command}"/&
<ContextMenu>
<MenuItem Header="Item 1" Command="{Binding Item1Command}"/>
<MenuItem Header="Item 2" Command="{Binding Item2Command}"/>
<MenuItem Header="Item 3" Command="{Binding Item3Command}"/>
</ContextMenu>
命令
绑定设置了CanExecute
,因此当它为false时,MenuItem
具有IsEnabled=false
。当IsEnabled=false
时,该触发器将设置Visibility=Collapsed
,反之亦然。我遇到的问题是,如果禁用了所有MenuItem
s,则ContextMenu
仍然显示为一个小的空白矩形。我有很多ContextMenu
s,那么实现这一点的最模块化的方法是什么呢?我最终做了一个不同的解决方法,而不是隐藏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;
}
}
}
EventManager.RegisterClassHandler(typeof(FrameworkElement)、ContextMenuOpenEvent、,
新的路由EventHandler(OnContextMenuoOpening);
私有void OnContextMenuOpening(对象发送方,路由目标)
{
var-control=(发送方作为框架元素);
var menu=control==null?null:control.ContextMenu;
如果(菜单!=null)
{
var items=menu.items.Cast();
if(items.All(i=>i.Visibility!=Visibility.Visibility))
{
e、 已处理=正确;
}
}
}
如果有一种更好的方法可以做到这一点,而不需要代码隐藏,那么对于父控件,我愿意接受其他解决方案。这里有一段xaml,它将帮助您开始使用“条件”上下文菜单。
请注意:这只是一个起点
<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>
1.
2.
我发现解决这个问题的唯一方法是通过attached属性,但它看起来对我来说是可以接受的。首先定义一个具有属性的类:
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;
}
}
}
}
public类ContextMenuExtension
{
公共静态bool GetHideOnEmpty(DependencyObject obj)
{
返回(bool)对象GetValue(HideOnEmptyProperty);
}
公共静态void SetHideOnEmpty(DependencyObject对象,布尔值)
{
对象设置值(HideOnEmptyProperty,值);
}
公共静态只读从属属性HideOnEmptyProperty=
DependencyProperty.RegisterAttached(“HideOnEmpty”、typeof(bool)、typeof(ContextMenuExtension)、新UIPropertyMetadata(false、HideOnEmptyChanged));
私有静态void HideOnEmptyChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var contextMenu=d作为contextMenu;
if(contextMenu==null)
返回;
contextMenu.Loaded+=contextMenu\u Loaded;
}
已加载私有静态void ContextMenu_(对象发送方,路由目标)
{
var contextMenu=发送方作为contextMenu;
var hideOnEmpty=GetHideOnEmpty(上下文菜单);
HideContextMenu(上下文菜单,hideOnEmpty);
}
//这是我们检查是否所有项目都不可见的地方
私有静态无效HideContextMenu(上下文菜单上下文菜单,布尔值)
{
//首先,我们必须知道HideOnEmpty属性是否设置为true。
if(val)
{
//检查上下文菜单是否为null或空
if(contextMenu.Items==null | | contextMenu.Items.Count<1)
contextMenu.Visibility=Visibility.Collapsed;//隐藏contextMenu
其他的
{
布尔隐藏=真;
//检查是否所有项目都不可见。
foreach(contextMenu.Items中的MenuItem i)
{
如果(i.Visibility==Visibility.Visibility)
{
隐藏=假;
打破
}
}
//如果上面的一个或多个项目可见,我们不会隐藏contextMenu。
如果(!隐藏)
contextMenu.Visibility=可见性.Visibility;
其他的
contextMenu.Visibility=Visibility.Collapsed;
}
}
}
}
然后在XAML中,使用ContextMenu向上面的类添加名称空间,并执行以下操作:
<ContextMenu cc:ContextMenuExtension.HideOnEmpty="True">
<MenuItem Header="Delete" Command="<delete_command>" Visibility="Collapsed"/>
</ContextMenu>
每次用户右键单击查看菜单时,它都会从“ContextMenuExtension”类触发“HideContextMenu”方法,如果没有项目或所有项目都不可见,则隐藏整个ContextMenu。您可以将ContextMenu的可视性绑定到项目,如果没有可见项目,则编写转换器。据我所知,绑定在DataContext中,DataContext是我的ViewModel,但是我的菜单项是在视图中显式定义的。我理解转换器部分,但是如何仅通过更改视图来完成前半部分?更不用说,我不确定Items集合是否会触发NotifyPropertyChanged,以使转换器根据MenuItems的触发可见性实际工作。我只是尝试了StaticResource,结果正是您所需要的。如果你愿意,我可以把代码贴在这里让你检查一下。这不是一个直接的解决方案,但它应该给你一个关于如何做的好主意。