CanExecute()返回true,按钮仍然被禁用

时间:2015-03-09 09:35:05

标签: c# winrt-xaml win-universal-app

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

此特定情况下的问题是即使提升.RaiseCanExecuteChanged()方法后按钮仍处于停用状态,CanExecute()会返回true

我原本以为这可能是由于过多调用手动提升属性更改的通知,因此收紧了我的代码部分,以便只根据需要引发方法,并在需要更改按钮的时候状态。即便如此,尽管CanExecute()返回true,该按钮仍处于停用状态。 如果我注释掉CanExecute()中的所有检查并且默认为true,则按钮按预期启用,并且当点击时触发预期的Execute()函数,因此看起来{{1}的初始化好的如果我然后让检查重新进入,并在每次RelayCommand被触发时逐步执行,当它返回true时,该按钮不会被启用。

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

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

viewmodel构造函数的最后一行是RelayCommand;

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;
}

3 个答案:

答案 0 :(得分:2)

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

  

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;
    }
}

这基本上会根据(通常在我的View模型中)的任何属性的更改来刷新CanExecute。如果你在ObservableCollection中的模型中有潜在的变化,这是不够的,但它对整个事情来说是个不错的开始。

您可能根本没有遇到此问题。并且你要召集事件,它返回真实,仍然无法正常工作。如果这就是正在发生的事情,它只需要是您的代码,因为命令适用于数千个应用程序。但是,如果你想把你的代码发给我,我会看看。

祝你好运!

答案 1 :(得分:1)

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

Jerry's answer很可能是正确的,问题是RaiseCanExecuteChanged在ICommand的实现中没有自动引发,但提供的代码示例重新引入了导致它被取出的完全相同的问题首先 - 只要任何属性发生变化,它就会引发CanExecuteChanged,从而导致调用CanExecute远远超出必要的范围。

PropertyChanged事件处理程序应该包含一个检查,如果更改的属性是CanExecute中使用的属性,则只引发CanExecuteChanged。

因为您的CanExecute是

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;
    }
}

答案 2 :(得分:0)

如果您使用的是Mvvm Light,请确保包含GalaSoft.MvvmLight.CommandWpf命名空间而不是GalaSoft.MvvmLight.Command命名空间。 (见MVVM RelayCommand CanExecute上的第二个答案)