简体   繁体   中英

Button IsEnabled state not updating based on CanExecute return value

I have a button in a Windows 8.1 'universal' app bound to a RelayCommand that is not updating to disabled as expected, based on the return value of CanExecute() . Implementation details are below, but basically, the RelayCommand is initialised to return false, changes to enabled as expected, but doesn't return to disabled as expected.

UI flow is once the user selects an item from a combobox (bound to a property), the .RaiseCanExecuteChanged() is called and returns true, and the button updates to enabled as expected. A second combobox (now visible) is bound to another property, which when changed runs a method to set a validation property, which when changed calls .RaiseCanExecuteChanged() . This time, when I expect to see the button disabled, it isn't, despite CanExecute() returning false. Funnily enough, the delegate method that is the action doesn't run if the button is then clicked, but I need the button disabled, since the click method of the button is Frame.GoBack()

RelayCommand class:

public class RelayCommand : ICommand
{
    private readonly Action _execute;
    private readonly Func<bool> _canExecute;

    public event EventHandler CanExecuteChanged;

    public RelayCommand(Action execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action execute, Func<bool> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute();
    }

    public void Execute(object parameter)
    {
        _execute();
    }

    public void RaiseCanExecuteChanged()
    {
        var handler = CanExecuteChanged;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

CanExecute method:

private bool CanAcceptTransportProfile()
    {
        if (IsTPInEditMode == false) return false;
        if (SelectedTransport == null) return false;
        if (IsSubPropertiesValid == false) return false;
        return true;
    }

Initial property and change:

public Unit SelectedTransport
    {
        get { return _selectedTransport; }
        set
        {
            if (_selectedTransport != value)
            {
                _selectedTransport = value;
                RaisePropertyChanged("SelectedTransport");
                OnSelectedTransportChange();
            }
        }
    }

private void OnSelectedTransportChange()
    {
        switch (SelectedTransport == null)
        {
            case true:
                IsTransportSelected = false;
                IsUnitsPerTransportValid = true;
                IsSharingWithValid = true;
                IsNestingValid = true;
                break;
            case false:
                IsTransportSelected = true;
                ShowUnitsPerTransportSelector = IsAllowedToShareTransport ? false : true;
                break;
        }
        CommandAcceptTransportProfile.RaiseCanExecuteChanged();
    }

Second property change:

public int UnitsPerTransport
    {
        get { return _unitsPerTransport; }
        set
        {
            if (_unitsPerTransport != value)
            {
                _unitsPerTransport = value;
                RaisePropertyChanged("UnitsPerTransport");
                OnUnitsPerTransportChange();
            }
        }
    }

private void OnUnitsPerTransportChange()
    {
        List<int> unitoptions = UnitHelper.UnitRangeFromSquadSize(this.SquadSize);
        if (!unitoptions.Contains(_unitsPerTransport))
        {
            foreach (int num in unitoptions)
            {
                if (_unitsPerTransport < num)
                {
                    if (num % _unitsPerTransport != 0)
                    { goto Invalid; }
                }
                else
                {
                    if (_unitsPerTransport % num != 0)
                    { goto Invalid; }
                }
            }
            goto Valid;
        }
        else
        { goto Valid; }

    Valid:
        IsUnitsPerTransportValid = true;
        IsSubPropertiesValid = (IsUnitsPerTransportValid && IsNestingValid && IsSharingWithValid && IsTotalUnitsRequiredValid) ? true : false;
    Invalid:
        IsUnitsPerTransportValid = false;
        IsSubPropertiesValid = false;
    }

IsSubPropertiesValid raises CommandAcceptTransportProfile.RaiseCanExecuteChanged() when it changes. The UnitHelper is a static class and just returns a list of ints . the method then checks the selected int from the combobox and goes to valid/invalid accordingly. it is when this sets IsSubPropertiesValid to false I expect to see the button become disabled, and it isn't.

I have been using the RelayCommand in this fashion throughout my project and it has worked in every instance as expected, except this one, which has more complex validation/Onproperty change calls surrounding it, so I suspect it has something to do with that, but it is beyond my self taught knowledge to resolve.

Try to implement INotifyPropertyChanged , a sample can look like this:

public class RelayCommand : ICommand, INotifyPropertyChanged
{
    #region INotify
    public event PropertyChangedEventHandler PropertyChanged;

    public void RaiseCanExecuteChanged()
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, "CanExecute");
        }
    }
    #endregion

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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