简体   繁体   English

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

[英]CanExecute() returns true and button is still disabled

I have a BottomAppBar.AppBarButton in a Windows Phone specific page, that is bound to a relay command. 我在Windows Phone特定页面中有一个BottomAppBar.AppBarButton ,它绑定到中继命令。 The code, binding and viewmodel implementation have all been used in basically the same way on other pages in the project and works exactly as expected there. 代码,绑定和viewmodel的实现在项目的其他页面上都以基本上相同的方式使用,并且完全按预期运行。

The issue in this particular scenario is that the button remains disabled even after raising the .RaiseCanExecuteChanged() method, and the CanExecute() returns true . 在这种特定情况下的问题是,即使在提高.RaiseCanExecuteChanged()方法之后,按钮仍保持禁用状态,并且CanExecute()返回true

I originally thought that it might be due to excess calls to manually raising the notification with property changes, so have tightened that part of my code so that the method is only raised as needed, and when it is needed to change the button's status. 我原本以为这可能是由于过多的调用而导致的,这些调用是通过手动更改属性更改来手动引发通知的,所以收紧了我那部分代码,以便仅在需要时以及在需要更改按钮状态时才引发该方法。 Even still, the button remains disabled despite CanExecute() returning true . 即使CanExecute()返回true ,按钮仍保持禁用CanExecute() If I comment out all the checks in CanExecute() and default to true, the button is enabled as expected, and when tapped fires the expected Execute() function, so it appears that the initialization of the RelayCommand is ok. 如果我注释掉CanExecute()所有检查并将其默认设置为true,则该按钮将按预期启用,并且在点RelayCommand会触发预期的Execute()函数,因此似乎可以执行RelayCommand的初始化。 If I then let the checks back in, and run step through each time CanExecute() is fired, when it returns true, the button doesn't become enabled. 如果我然后放回检查,并在每次触发CanExecute()CanExecute() ,则当它返回true时,该按钮不会启用。

Any ideas? 有任何想法吗? For what its worth, I've added code below, but I don't think that is the cause. 对于它的价值,我在下面添加了代码,但我不认为这是原因。

RelayCommand class is the standard class that comes with the HubApp in VS, so I will omit that code. RelayCommand类是VS中HubApp随附的标准类,因此我将省略该代码。

last line of the viewmodel constructor is the RelayCommand; viewmodel构造函数的最后一行是RelayCommand;

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

Can Add is; 可以添加是;

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

And finally, the button binding 最后,按钮绑定

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

I'd probably bet your problem has to do with RaiseCanExecuteChanged(). 我可能打赌您的问题与RaiseCanExecuteChanged()有关。 This is especially true if you are used to WPF and how it automatically refreshes CanExecute for you. 如果您习惯使用WPF及其如何为您自动刷新CanExecute,则尤其如此。 Check out this Delegate Command implementation: 查看此Delegate Command实现:

http://codepaste.net/ho9s5a http://codepaste.net/ho9s5a

The ICommand interface defines the event CanExecuteChanged which instructs the button (or UI Element) to refresh its Enabled status. ICommand接口定义事件CanExecuteChanged ,该事件指示按钮(或UI元素)刷新其“ Enabled状态。 In WPF, this was raised constantly by the static, command manager. 在WPF中,这是由静态命令管理器不断提出的。 This does not exist in WinRT. 在WinRT中不存在。 In WPF, because it was raised so frequently, WPF developers had to be careful that CanExecute() was not an expensive operation. 在WPF中,由于它频繁出现,因此WPF开发人员必须注意CanExecute()不是昂贵的操作。 WinRT provides for expensive tests, but consequently requires the developer to raise the event manually. WinRT提供了昂贵的测试,但因此要求开发人员手动引发事件。 I hope this makes sense. 我希望这是有道理的。

One way I handle this is: 我处理此问题的一种方法是:

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

This basically refreshes the CanExecute based on the change of any property in (usually in my View Model). 这基本上是基于(通常在我的View模型中)任何属性的更改刷新CanExecute的。 This is not sufficient if you have potential changes in models that you have in an ObservableCollection, but it's a nice start to the whole thing. 如果您对ObservableCollection中的模型进行了潜在的更改,这还不够,但这是整个过程的一个很好的开始。

There's a possibility that you don't have this problem at all. 您可能根本没有这个问题。 And that you are calling to raise the event, it is returning true, and is still not working. 而且您正在打电话提出该事件,该事件返回true,并且仍然无法正常工作。 If that is what is happening, it just has to be your code because Commands are working for thousands of apps. 如果正在发生这种情况,那么它就必须是您的代码,因为Commands正在为数千个应用程序工作。 But, if you want to send me your code, I'll take a look. 但是,如果您想将代码发送给我,我会看一下。

Best of luck! 祝你好运!

I know this is a late answer, but this post is being linked in another question so I feel like I should post a better code sample. 我知道这是一个较晚的答案,但此帖子已链接到另一个问题,因此我觉得我应该发布一个更好的代码示例。

Jerry's answer is most likely correct that the problem is RaiseCanExecuteChanged is not raised automatically in that implementation of ICommand, however the code sample provided re-introduces the exact same problem that caused it to be taken out in the first place - it raises CanExecuteChanged whenever any property changes, resulting in CanExecute being called far more than necessary. 杰里的答案很可能是正确的,问题是在该ICommand实现中不会自动引发RaiseCanExecuteChanged ,但是提供的代码示例重新引入了导致该错误首先出现的相同问题-每当问题时,它都会引发CanExecuteChanged属性更改,导致CanExecute的调用远远超出了必要。

The PropertyChanged event handler should include a check and only raise CanExecuteChanged if the property changed is one that is used in CanExecute. PropertyChanged事件处理程序应包括一个检查,并且如果更改的属性是CanExecute中使用的属性,则仅引发CanExecuteChanged。

Since your CanExecute is 由于您的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;
}

then the event handler needs to only raise CanExecuteChanged if one of those for properties changes 那么事件处理程序仅在属性之一更改时才需要引发CanExecuteChanged

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

If you are using Mvvm Light, make sure you are including the GalaSoft.MvvmLight.CommandWpf namespace instead of the GalaSoft.MvvmLight.Command namespace. 如果使用的是Mvvm Light,请确保包含GalaSoft.MvvmLight.CommandWpf命名空间,而不是GalaSoft.MvvmLight.Command命名空间。 (See the second answer on MVVM RelayCommand CanExecute ) (请参阅有关MVVM RelayCommand CanExecute的第二个答案)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM