I have several ContextMenus with items defined as such:
<ContextMenu>
<MenuItem Header="Item 1" Command="{Binding Item1Command}"/>
<MenuItem Header="Item 2" Command="{Binding Item2Command}"/>
<MenuItem Header="Item 3" Command="{Binding Item3Command}"/>
</ContextMenu>
The Command
bindings have CanExecute
set so that when it's false, the MenuItem
has IsEnabled=false
. This goes on with a trigger that sets Visibility=Collapsed
when IsEnabled=false
and the opposite happens as well. The problem I'm running into is if all MenuItem
s are disabled, the ContextMenu
still shows up as a small blank rectangle. I have a lot of ContextMenu
s, so what would be the most modular way to implement this?
I ended up doing a different workaround instead of hiding the visibility of the ContextMenu. It seems like it may be less efficient since it checks for all FrameworkElement ContextMenus, but it is working:
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;
}
}
}
If there is a better way to do this without having code behind, for the parent control nonetheless, I'm open to alternative solutions.
Here is a piece of xaml that will get you started with "Conditional" ContextMenu.
Please note: this is only starting point
<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>
The only way I found to solve that is via attached property, but it looks quite acceptable to me. First define a class with property:
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;
}
}
}
}
Then in XAML with your ContextMenu add a namespace to class above and do following:
<ContextMenu cc:ContextMenuExtension.HideOnEmpty="True">
<MenuItem Header="Delete" Command="<delete_command>" Visibility="Collapsed"/>
</ContextMenu>
Every time user right clicks to see the menu, it will trigger "HideContextMenu" method from "ContextMenuExtension" class and if no items or all of them are not Visible - hide entire ContextMenu.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.