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

C# CanExecute()返回true,但按钮仍处于禁用状态,c#,winrt-xaml,win-universal-app,C#,Winrt Xaml,Win Universal App,我在Windows Phone特定页面中有一个BottomAppBar.AppBarButton,它绑定到中继命令。代码、绑定和viewmodel实现在项目中的其他页面上都以基本相同的方式使用,并且完全按照预期工作 此特定场景中的问题是,即使在引发.raiseCanExecutChanged()方法后,按钮仍保持禁用状态,CanExecute()返回true 我最初认为这可能是由于调用过多,需要通过属性更改手动引发通知,因此我收紧了代码的这一部分,以便只在需要时以及需要更改按钮状态时才引发该方法

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

此特定场景中的问题是,即使在引发
.raiseCanExecutChanged()
方法后,按钮仍保持禁用状态,
CanExecute()
返回
true

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

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

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

viewmodel构造函数的最后一行是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;
}
private bool canadstriketeam()
{
//if(NameWorking==string.Empty)返回false;
//if(productworking==string.Empty)返回false;
//if(PointsLimitWorking<1)返回false;
//如果(!IsValidTeamWorking)返回false;
返回true;
}
最后是按钮绑定

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

我敢打赌你的问题与RaiseCanceTechChanged()有关。如果您习惯了WPF以及它如何为您自动刷新CanExecute,这一点尤其正确。检查此委托命令实现:

ICommand
界面定义了事件
CanExecuteChanged
,该事件指示按钮(或UI元素)刷新其
启用状态。在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中的模型中有潜在的更改,这是不够的,但这是整个过程的一个良好开端

有可能你根本没有这个问题。如果您正在呼叫以引发该事件,它将返回true,并且仍然不起作用。如果这就是正在发生的事情,那就必须是你的代码,因为命令适用于数千个应用程序。但是,如果你想给我你的密码,我会看一看


祝你好运

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

最有可能是正确的,问题是在ICommand的该实现中未自动引发
RaiseCanecuteChanged
,但是提供的代码示例重新引入了导致其首先被删除的完全相同的问题-每当任何属性更改时,它都会引发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;
}

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

是否为
AppBarButton
设置了任何样式?是否有可能在非调度程序线程上执行RaiseCanceTechChanged()调用?是否使用MVVM Light?MVVM Light V5中存在一个bug,可能会导致RaiseCanceTechChanged出现问题(此处的详细信息和解决方案:)。@PatrickHofman在我的xaml中没有明确设置样式,因此我假设它是默认的按钮样式。@PeterLillevold能否请您详细说明我如何检查此项,因为到目前为止,我还没有在我的自我教导中遇到任何线程相关的问题。谢谢Jerry。我开始认为这是我在代码中做了一些不同的事情,但我无法定位在哪里。我刚刚执行了两个以上的调试步骤,发现如果我保留对
NameWorking
PointsLimitWorking
的检查,那么当返回
true
时,按钮将启用。当我返回其他两个检查中的任何一个时,当返回true时按钮不会启用。我很难找到导致问题的原因。如果您提供查看我的代码仍然是开放的,我想接受它。让我知道怎么做,我会将解决方案发送给你。请在发送给我之前简化你的项目。请确保我可以打开拉链,并建立它的罚款。jnixon@microsoft这是我的电子邮件。我可能需要几天的时间才能找到答案。这个答案已经发布很久了,我已经从这个特定的问题开始了,但是这个答案在其他问题上帮助了我,最重要的是,无意中编写了代码,导致其他按钮出现同样的问题。标记为答案的。
this.PropertyChanged += (s, e) => 
{
    switch (e.PropertyName)
    {
        case "NameWorking":
        case "FactionWorking":
        case "PointsLimitWorking":
        case "IsValidTeamWorking":
            AddStrikeTeamCommand.RaiseCanExecuteChanged();
            break;
    }
}