By default menu items become disabled when its command cannot be executed (CanExecute = false). What is the easiest way to make the menu item visible/collapsed based on the CanExecute method?
6 Answers
Thanks for the solution. For those wanting explicit XAML this might help:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter" />
</Window.Resources>
<ContextMenu x:Key="innerResultsContextMenu">
<MenuItem Header="Open"
Command="{x:Static local:Commands.AccountOpened}"
CommandParameter="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"
CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"
Visibility="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}, Mode=OneWay, Converter={StaticResource booleanToVisibilityConverter}}"
/>
</ContextMenu>
In my case, the context menu is a resource, so the binding for the visibility must use the RelativeSource Self binding setup.
As a side, for the CommandParameter, you might also pass the DataContext of the item whom was clicked to open the context menu. And in order to route the command bindings to the parent window, you will need to set the CommandTarget accordingly also.

- 4,897
- 5
- 30
- 41

- 15,219
- 3
- 51
- 63
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</Trigger>
</Style.Triggers>
CanExecute
toggles the IsEnabled
property so just watch this and keep everything in the UI. Create a separate style if you want to reuse this.

- 1,221
- 12
- 22
-
This is perfect - worked like a charm (although I used a direct binding with a bool to visibility converter instead of a trigger, the idea is the same) – 17 of 26 Jun 12 '12 at 18:24
-
7The visibility should be set to `Collapsed` as otherwise the hidden menu item will still occupy space. – Roman Reiner Jul 01 '14 at 09:50
-
Yes, this is a better solution although as per Roman's suggestion, visibility should be set to Collapsed – Gareth Oct 25 '16 at 17:00
-
Changed visibility to 'Collapsed'. – rjarmstrong Feb 21 '17 at 22:10
-
changing the visibility is a change to style so using a style makes more sense than a direct binding – MikeT Apr 09 '18 at 13:08
-
@MikeT I agree. It's easier to read and re-usable on several menu items or buttons without copy-paste. – Martin Braun Nov 05 '21 at 03:09
You can simply bind Visibility to IsEnabled (set to false on CanExecute == false). You still would need an IValueConverter to convert the bool to visible/collapsed.
public class BooleanToCollapsedVisibilityConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//reverse conversion (false=>Visible, true=>collapsed) on any given parameter
bool input = (null == parameter) ? (bool)value : !((bool)value);
return (input) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}

- 3,427
- 15
- 18
-
5This is a bit more effort than necessary you can just use a trigger – rjarmstrong Apr 12 '12 at 11:11
Microsoft provides a BooleanToVisibilityConverter.
http://msdn.microsoft.com/en-us/library/system.windows.controls.booleantovisibilityconverter.aspx

- 2,704
- 2
- 29
- 48
I don't know if this is the easiest way, but you can always create a property which returns the CanExecute()
and then bind the Visibility of your element to this property, using a IValueConverter
to convert the boolean to Visibility.

- 7,483
- 5
- 44
- 67
-
This answer does not help much, but I'm giving it +1 to level those negative points that I completely do not understood why someone has given. While this answer is not too helpful, ALL things mentioned in it are VALID and moreover, all other positively-marked answers DO USE the things mentioned. The least pointvalue this answer deserves is zero, not negatives! – quetzalcoatl Dec 07 '11 at 12:48
-
This was my initial thought, but how would you gain access to the (object param) parameter from within this new property, and pass it to CanExecute()? – Matt Dec 07 '11 at 16:41
Binding Visibility to IsEnabled does the trick, but the required XAML is unpleasantly long and complicated:
Visibility="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}, Mode=OneWay, Converter={StaticResource booleanToVisibilityConverter}}"
You can use an attached property to hide all the binding details and clearly convey your intent.
Here is the attached property:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace MyNamespace
{
public static class Bindings
{
public static bool GetVisibilityToEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(VisibilityToEnabledProperty);
}
public static void SetVisibilityToEnabled(DependencyObject obj, bool value)
{
obj.SetValue(VisibilityToEnabledProperty, value);
}
public static readonly DependencyProperty VisibilityToEnabledProperty =
DependencyProperty.RegisterAttached("VisibilityToEnabled", typeof(bool), typeof(Bindings), new PropertyMetadata(false, OnVisibilityToEnabledChanged));
private static void OnVisibilityToEnabledChanged(object sender, DependencyPropertyChangedEventArgs args)
{
if (sender is FrameworkElement element)
{
if ((bool)args.NewValue)
{
Binding b = new Binding
{
Source = element,
Path = new PropertyPath(nameof(FrameworkElement.IsEnabled)),
Converter = new BooleanToVisibilityConverter()
};
element.SetBinding(UIElement.VisibilityProperty, b);
}
else
{
BindingOperations.ClearBinding(element, UIElement.VisibilityProperty);
}
}
}
}
}
And here is how you would use it:
<Window x:Class="MyNamespace.SomeClass"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyNamespace">
<ContextMenu x:Key="bazContextMenu">
<MenuItem Header="Open"
Command="{x:Static local:FooCommand}"
local:Bindings.VisibilityToEnabled="True"/>
</ContextMenu>
</Window>

- 387
- 3
- 10