WPF - как скрыть пункт меню, если команда CanExecute имеет значение false? - PullRequest
47 голосов
/ 21 сентября 2010

По умолчанию пункты меню становятся недоступными, когда его команда не может быть выполнена (CanExecute = false). Какой самый простой способ сделать элемент меню видимым / свернутым на основе метода CanExecute?

Ответы [ 6 ]

51 голосов
/ 08 декабря 2010

Спасибо за решение. Для тех, кто хочет явный XAML, это может помочь:

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

В моем случае контекстное меню является ресурсом, поэтому привязка для видимости должна использовать настройку привязки RelativeSource Self.

В качестве стороны, для CommandParameter вы также можете передать DataContext элемента, по которому щелкнули, чтобы открыть контекстное меню. А для того, чтобы направить привязки команд к родительскому окну, вам также необходимо соответствующим образом установить CommandTarget.

44 голосов
/ 12 апреля 2012
<Style.Triggers>
    <Trigger Property="IsEnabled" Value="False">
        <Setter Property="Visibility" Value="Collapsed"/>
    </Trigger>
</Style.Triggers>

CanExecute переключает свойство IsEnabled, поэтому просто наблюдайте за этим и сохраняйте все в интерфейсе пользователя. Создайте отдельный стиль, если вы хотите использовать это снова.

43 голосов
/ 21 сентября 2010

Вы можете просто привязать Visibility к IsEnabled (установить в false на CanExecute == false)Вам все еще понадобится IValueConverter, чтобы конвертировать bool в видимый / свернутый.

8 голосов
/ 08 марта 2011

Microsoft предоставляет BooleanToVisibilityConverter.
http://msdn.microsoft.com/en-us/library/system.windows.controls.booleantovisibilityconverter.aspx

1 голос
/ 21 сентября 2010

Я не знаю, является ли это самым простым способом, но вы всегда можете создать свойство, которое возвращает CanExecute(), а затем связать видимость вашего элемента с этим свойством, используя IValueConverter для преобразования логического значения вВидимость.

0 голосов
/ 19 мая 2019

Привязка Видимость к IsEnabled делает свое дело, но требуемый XAML неприятно длинный и сложный:

Visibility="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}, Mode=OneWay, Converter={StaticResource booleanToVisibilityConverter}}"

Вы можете использовать присоединенное свойство, чтобы скрыть все детали привязки и четко передать ваше намерение.

Вот прикрепленное свойство:

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

А вот как вы бы его использовали:

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