【问题标题】:WPF - how to hide menu item if command's CanExecute is false?WPF - 如果命令的 CanExecute 为假,如何隐藏菜单项?
【发布时间】:2011-04-15 06:28:55
【问题描述】:

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

【问题讨论】:

    标签: wpf command contextmenu menuitem


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:
      <Style.Triggers>
          <Trigger Property="IsEnabled" Value="False">
              <Setter Property="Visibility" Value="Collapsed"/>
          </Trigger>
      </Style.Triggers>
      

      CanExecute 切换IsEnabled 属性,所以请注意这一点并将所有内容保留在 UI 中。如果您想重用它,请创建一个单独的样式。

      【讨论】:

      • 这是完美的——就像一个魅力一样工作(虽然我使用了一个直接绑定到可见性转换器而不是触发器,但想法是一样的)
      • 可见性应设置为Collapsed,否则隐藏的菜单项仍会占用空间。
      • 是的,这是一个更好的解决方案,尽管按照 Roman 的建议,可见性应该设置为 Collapsed
      • 将可见性更改为“已折叠”。
      • 更改可见性是对样式的更改,因此使用样式比直接绑定更有意义
      【解决方案3】:

      您可以简单地将 Visibility 绑定到 IsEnabled(在 CanExecute == false 上设置为 false)。 你仍然需要一个 IValueConverter 来将 bool 转换为可见/折叠。

          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
          }
      

      【讨论】:

      • 这比你需要的更多的努力,你可以使用触发器
      【解决方案4】:

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 这个答案没有多大帮助,但我给它 +1 以平衡那些我完全不明白为什么有人给出的负面观点。虽然这个答案没有太大帮助,但其中提到的所有内容都是有效的,此外,所有其他正面标记的答案都使用提到的内容。这个答案应得的最低分值是零,而不是负数!
        • 这是我最初的想法,但是如何从这个新属性中访问(对象参数)参数,并将其传递给 CanExecute()?
        【解决方案6】:

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

        【讨论】:

          猜你喜欢
          • 2010-12-11
          • 1970-01-01
          • 2015-11-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多