Метод CanExecute WPF-Prism не вызывается - PullRequest
20 голосов
/ 15 марта 2010

Я кодирую простой вход в систему UserControl с двумя текстовыми полями (имя пользователя и пароль) и кнопкой входа в систему. Я хочу, чтобы кнопка «Вход в систему» ​​была включена только при заполнении полей имени пользователя и пароля. Я использую Prism и MVVM. LoginViewModel содержит свойство с именем LoginCommand, которое связано с кнопкой входа в систему. У меня есть метод CanLoginExecute () в моем ViewModel, но он срабатывает только при запуске приложения, а затем никогда больше. Таким образом, кнопка входа никогда не активируется. Чего мне не хватает?

Вот мой xaml:

<TextBox x:Name="username"
    Text="{Binding Path=Username, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
<TextBox x:Name="password"
    Text="{Binding Path=Password, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
<Button Content="Login"
    cmnd:Click.Command="{Binding LoginCommand}" />

Вот моя ViewModel

class LoginViewModel : IDataErrorInfo, INotifyPropertyChanged
{
    public LoginViewModel()
    {
        this.LoginCommand =
            new DelegateCommand<object>(
                this.LoginExecute, this.CanLoginExecute);
    }

    private Boolean CanLoginExecute(object dummyObject)
    {
        return (string.IsNullOrEmpty(Username) ||
                string.IsNullOrEmpty(Password)) ? false : true;
    }

    private void LoginExecute(object dummyObject)
    {
        if (CheckCredentials(Username, Password))
        {
            ....
        }
    }

    #region IDataErrorInfo Members

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    public string this[string columnName]
    {
        get
        {
            string result = null;
            if (columnName == "Username")
            {
                if (string.IsNullOrEmpty(Username))
                    result = "Please enter a username";
            }
            else if (columnName == "Password")
            {
                if (string.IsNullOrEmpty(Password))
                    result = "Please enter a password";
            }
            return result;
        }
    }

    #endregion // IDataErrorInfo Members

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion // INotifyPropertyChanged Members

    #region Properties

    private String _username;
    public String Username
    {
        get { return _username; }
        set
        {
            if (value == _username)
                return;
            _username = value;
            this.OnPropertyChanged("Username");
        }
    }

    private String _password;
    public String Password
    {
        get { return _password; }
        set
        {
            if (value == _password)
                return;
            _password = value;
            this.OnPropertyChanged("Password");
        }
    }

    public ICommand LoginCommand { get; private set; }

    #endregion // Properties
}

Ответы [ 4 ]

42 голосов
/ 15 марта 2010

Скорее всего, связанный элемент управления никогда больше не запрашивает состояние CanExecute . Вам необходимо вызывать метод RaiseCanExecuteChanged для DelegateCommand всякий раз, когда вы обнаруживаете условие, которое изменяет состояние CanExecute команды. Это сигнализирует связанному элементу управления обновить состояние CanExecute .

8 голосов
/ 22 мая 2010

Код для RaiseCanExecuteChanged:

    private void RaiseCanExecuteChanged()
    {
        DelegateCommand<object> command = LoginCommand as DelegateCommand<object>;
        command.RaiseCanExecuteChanged();
    }

    public const string UsernameProperty = "Username";
    private String _username;
    public String Username
    {
        get { return _username; }
        set
        {
            _username = value;
            this.NotifyPropertyChanged(UsernameProperty);
            RaiseCanExecuteChanged();
        }
    }
5 голосов
/ 05 мая 2018

Начиная с Prism6 DelegateCommand может "наблюдать" ваши свойства. Означает каждый раз, когда ваше свойство изменяется, вызывается CanExecute-метод. Хорошо, что вы избавляетесь от RaiseCanExecuteChanged в Propertysetter. Вы также можете вызвать этот метод по цепочке, если хотите наблюдать больше свойств:

public LoginViewModel()
{
    this.LoginCommand =
        new DelegateCommand<object>(
            this.LoginExecute, this.CanLoginExecute).ObservesProperty(() => Username).ObservesProperty(() => Password);
}

Кроме того, если вы просто хотите, чтобы ваш DelegateCommand вызывался в зависимости от состояния логического свойства, вы можете использовать .ObservesCanExecute(()=> BoolProp)

public LoginViewModel()
{
    this.LoginCommand =
        new DelegateCommand<object>(
            this.LoginExecute).ObservesCanExecute(()=> IsServerOnline).ObservesProperty(() => Username).ObservesProperty(() => Password);
}

Вам больше не нужно this.CanLoginExecute.

2 голосов
/ 20 октября 2018

Вот небольшой обходной путь для Prism (протестировано с Prism.Core 7.1.0.431):

public class RelayCommand : DelegateCommand
{
    public RelayCommand(Action executeMethode) : base(executeMethode)
    {

    }

    public RelayCommand(Action executeMethode, Func<bool> canExecuteMethode) : base(executeMethode, canExecuteMethode)
    {

    }

    public override event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}
...