WPF - 如果命令的CanExecute为false,如何隐藏菜单项?

时间:2010-09-21 15:09:15

标签: wpf command contextmenu menuitem

默认情况下,菜单项在无法执行命令时会被禁用(CanExecute = false)。根据CanExecute方法使菜单项可见/折叠的最简单方法是什么?

6 个答案:

答案 0 :(得分:51)

感谢您的解决方案。对于那些想要显式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自绑定设置。

作为一方,对于CommandParameter,您还可以传递单击项目的DataContext以打开上下文菜单。并且为了将命令绑定路由到父窗口,您还需要相应地设置CommandTarget。

答案 1 :(得分:44)

<Style.Triggers>
    <Trigger Property="IsEnabled" Value="False">
        <Setter Property="Visibility" Value="Collapsed"/>
    </Trigger>
</Style.Triggers>

CanExecute切换IsEnabled属性,因此只需观看此内容并将所有内容保留在用户界面中。如果要重复使用,请创建单独的样式。

答案 2 :(得分:43)

您可以简单地将Visibility绑定到IsEnabled(在CanExecute == false时设置为false)。 你仍然需要一个IValueConverter来将bool转换为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 :(得分:8)

答案 4 :(得分:1)

我不知道这是否是最简单的方法,但您始终可以创建一个返回CanExecute()的属性,然后使用IValueConverter将元素的可见性绑定到此属性将布尔值转换为可见性。

答案 5 :(得分:0)

将可见性绑定到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>