WPF - 如果命令的 CanExecute 为 false,如何隐藏菜单项?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3761672/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF - how to hide menu item if command's CanExecute is false?
提问by Gus Cavalcanti
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?
默认情况下,当其命令无法执行时,菜单项会被禁用(CanExecute = false)。基于 CanExecute 方法使菜单项可见/折叠的最简单方法是什么?
采纳答案by MrDosu
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.
您可以简单地将 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
}
回答by Reddog
Thanks for the solution. For those wanting explicit XAML this might help:
感谢您的解决方案。对于那些想要显式 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>
In my case, the context menu is a resource, so the binding for the visibility must use the RelativeSource Self binding setup.
就我而言,上下文菜单是一种资源,因此可见性的绑定必须使用 RelativeSource Self 绑定设置。
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.
另一方面,对于 CommandParameter,您还可以传递被单击以打开上下文菜单的项目的 DataContext。并且为了将命令绑定路由到父窗口,您还需要相应地设置 CommandTarget。
回答by rjarmstrong
<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.
CanExecute
切换IsEnabled
属性,因此只需观看此内容并将所有内容保留在 UI 中。如果您想重用它,请创建一个单独的样式。
回答by Jacob Foshee
Microsoft provides a BooleanToVisibilityConverter.
http://msdn.microsoft.com/en-us/library/system.windows.controls.booleantovisibilityconverter.aspx
Microsoft 提供了一个 BooleanToVisibilityConverter。
http://msdn.microsoft.com/en-us/library/system.windows.controls.booleantovisibilityconverter.aspx
回答by RoelF
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.
我不知道这是否是最简单的方法,但您始终可以创建一个属性,该属性返回CanExecute()
,然后将元素的可见性绑定到此属性,使用 aIValueConverter
将布尔值转换为可见性。
回答by SirCxyrtyx
Binding Visibility to IsEnabled does the trick, but the required XAML is unpleasantly long and complicated:
将可见性绑定到 IsEnabled 可以解决问题,但所需的 XAML 非常长且复杂:
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>