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

问题描述 投票:47回答:6

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

wpf command contextmenu menuitem
6个回答
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
    }

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 Self绑定设置。

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


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

CanExecute切换IsEnabled属性,所以只需观察并保持UI中的所有内容。如果要重复使用,请创建单独的样式。



1
投票

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


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>
© www.soinside.com 2019 - 2024. All rights reserved.