如果命令绑定解析为null,为什么会启用按钮

本文关键字:为什么 启用 按钮 null 命令 绑定 如果 | 更新日期: 2023-09-27 18:29:07

好的,XAML非常简单,使用MVVM绑定到视图模型上的ICommand SomeCommand { get; }属性:

<Button Command="{Binding Path=SomeCommand}">Something</Button>

如果SomeCommand返回null,则按钮启用。(与ICommand上的CanExecute(object param)方法无关,因为没有实例可调用该方法)

现在的问题是:为什么启用了按钮?你会如何解决这个问题?

如果你按下"启用"按钮,显然什么都不会调用。按钮看起来启用了,真难看。

如果命令绑定解析为null,为什么会启用按钮

我的同事找到了一个优雅的解决方案:使用绑定回退值!

public class NullCommand : ICommand
{
    private static readonly Lazy<NullCommand> _instance = new Lazy<NullCommand>(() => new NullCommand());
    private NullCommand()
    {
    }
    public event EventHandler CanExecuteChanged;
    public static ICommand Instance
    {
        get { return _instance.Value; }
    }
    public void Execute(object parameter)
    {
        throw new InvalidOperationException("NullCommand cannot be executed");
    }
    public bool CanExecute(object parameter)
    {
        return false;
    }
}

然后XAML看起来像:

<Button Command="{Binding Path=SomeCommand, FallbackValue={x:Static local:NullCommand.Instance}}">Something</Button>

这个解决方案的优点是,如果你打破德米特定律,并且在绑定路径中有一些点,每个实例可能变成null,它会更好地工作。

它是启用的,因为这是默认状态。自动禁用它将是一种武断的措施,还会引发其他问题。

如果要禁用没有关联命令的按钮,请使用适当的转换器将IsEnabled属性绑定到SomeCommand,例如:

[ValueConversion(typeof(object), typeof(bool))]
public class NullToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value !== null;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

与Jon的答案非常相似,您可以使用带有触发器的样式来标记在没有命令集时应该禁用的按钮。

<Style x:Key="CommandButtonStyle"
        TargetType="Button">
    <Style.Triggers>
        <Trigger Property="Command"
                    Value="{x:Null}">
            <Setter Property="IsEnabled"
                    Value="False" />
        </Trigger>
    </Style.Triggers>
</Style>

我更喜欢这种解决方案,因为它非常直接地解决了问题,而且不需要任何新的类型。