CanExecute() 返回 true,按钮仍处于禁用状态

本文关键字:于禁用 状态 按钮 返回 true CanExecute | 更新日期: 2024-11-06 03:44:43

我在Windows Phone特定页面中有一个绑定到中继命令的BottomAppBar.AppBarButton。代码、绑定和视图模型实现在项目的其他页面上都以基本相同的方式使用,并且完全按照预期工作。

此特定方案中的问题是,即使在引发 .RaiseCanExecuteChanged() 方法后,按钮仍处于禁用状态,并且CanExecute()返回true

我最初认为这可能是由于对手动引发属性更改通知的调用过多,因此收紧了我的代码的那部分,以便仅在需要时以及需要更改按钮状态时引发该方法。即使如此,尽管返回true CanExecute()按钮仍然处于禁用状态。如果我注释掉CanExecute()中的所有检查并默认为 true,则该按钮将按预期启用,并且在点击时触发预期的 Execute() 函数,因此看起来RelayCommand的初始化是可以的。如果我然后让签入,并在每次触发CanExecute()时单步运行,当它返回 true 时,按钮不会启用。

有什么想法吗?对于它的价值,我在下面添加了代码,但我认为这不是原因。

RelayCommand类是 VS 中 HubApp 附带的标准类,因此我将省略该代码。

视图模型构造函数的最后一行是 RelayCommand;

AddStrikeTeamCommand = new RelayCommand(async() => await AddStrikeTeam(), CanAddStrikeTeam);

可以添加是;

private bool CanAddStrikeTeam()
{
    //if (NameWorking == string.Empty) return false;
    //if (FactionWorking == string.Empty) return false;
    //if (PointsLimitWorking < 1) return false;
    //if (!IsValidTeamWorking) return false;
    return true;
}

最后,按钮绑定

<AppBarButton x:Name="accept" Icon="Accept" Label="accept"
              Command="{Binding AddStrikeTeamCommand}"/>

CanExecute() 返回 true,按钮仍处于禁用状态

我可能敢打赌你的问题与RaiseCanExecuteChanged()有关。如果您习惯了 WPF 以及它如何自动为您刷新 CanExecute,则尤其如此。查看此委托命令实现:

http://codepaste.net/ho9s5a

ICommand 接口定义事件CanExecuteChanged,该事件指示按钮(或 UI 元素)刷新其Enabled状态。在 WPF 中,静态命令管理器不断引发此问题。这在 WinRT 中不存在。在 WPF 中,由于它被频繁地引发,WPF 开发人员必须小心,CanExecute()不是一项昂贵的操作。WinRT 提供昂贵的测试,但因此需要开发人员手动引发事件。我希望这是有道理的。

我处理这个问题的一种方法是:

DelegateCommand _SaveCommand = null;
public DelegateCommand SaveCommand
{
    get
    {
        if (_SaveCommand != null)
            return _SaveCommand;
        _SaveCommand = new DelegateCommand
        (
            () =>
            {
                // TODO
            }, 
            () => true
        );
        this.PropertyChanged += (s, e) => _SaveCommand.RaiseCanExecuteChanged();
        return _SaveCommand;
    }
}

这基本上会根据任何属性的更改刷新 CanExecute(通常在我的视图模型中)。如果您在 ObservableCollection 中拥有的模型中有潜在的更改,这是不够的,但这是整个事情的一个很好的开始。

您有可能根本没有这个问题。并且您正在打电话提出事件,它返回为真,并且仍然不起作用。如果这是正在发生的事情,它必须是你的代码,因为命令适用于数千个应用程序。但是,如果你想把你的代码发给我,我会看看。

祝你好运!

我知道这是一个

迟到的答案,但是这篇文章被链接到另一个问题中,所以我觉得我应该发布一个更好的代码示例。

Jerry的回答很可能是正确的,即问题RaiseCanExecuteChanged在ICommand的实现中不会自动引发,但是提供的代码示例重新引入了导致它首先被取出的完全相同的问题 - 每当任何属性更改时,它都会引发CanExecuteChanged,导致CanExecute被调用远远超过必要。

PropertyChanged 事件处理程序应包括一个检查,并且仅当更改的属性是 CanExecute 中使用的属性时,才引发 CanExecuteChanged。

由于您的可以执行

private bool CanAddStrikeTeam()
{
    if (NameWorking == string.Empty) return false;
    if (FactionWorking == string.Empty) return false;
    if (PointsLimitWorking < 1) return false;
    if (!IsValidTeamWorking) return false;
    return true;
}

则事件处理程序只需要在属性之一更改时引发 CanExecuteChanged

this.PropertyChanged += (s, e) => 
{
    switch (e.PropertyName)
    {
        case "NameWorking":
        case "FactionWorking":
        case "PointsLimitWorking":
        case "IsValidTeamWorking":
            AddStrikeTeamCommand.RaiseCanExecuteChanged();
            break;
    }
}

如果您使用的是 Mvvm Light,请确保包含 GalaSoft.MvvmLight.CommandWpf 命名空间,而不是 GalaSoft.MvvmLight.Command 命名空间。(参见 MVVM 中继命令可以执行的第二个答案)