wpf prism command

No se llama al método WPF-Prism CanExecute



command (4)

Estoy codificando un UserControl de inicio de sesión simple con dos TextBoxes (nombre de usuario y contraseña) y un botón de inicio de sesión. Quiero que el botón Iniciar sesión se habilite solo cuando los campos de nombre de usuario y contraseña estén completos. Estoy usando Prism y MVVM. El LoginViewModel contiene una propiedad llamada LoginCommand que está vinculada al botón Iniciar sesión. Tengo un método CanLoginExecute () en mi ViewModel, pero se dispara solo cuando aparece la aplicación y nunca más. Así que el botón de inicio de sesión nunca está habilitado. ¿Qué me estoy perdiendo?

Aquí está mi 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}" />

Aquí está mi 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 }


A partir de Prism6, el DelegateCommand puede "observar" sus propiedades. Significa que cada vez que su propiedad está cambiando, se llama al método CanExecute. Lo bueno es que te deshaces de RaiseCanExecuteChanged en el Propertysetter. También puede hacer una cadena de ese método si desea observar más propiedades:

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

Además, si solo desea que se llame a su DelegateCommand dependiendo del estado de una propiedad booleana, puede usar .ObservesCanExecute(()=> BoolProp)

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

Usted no necesita this.CanLoginExecute más.


Aquí hay una pequeña solución para Prism (probado con 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; } } }


Código para 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(); } }


Es muy probable que el control enlazado nunca vuelva a solicitar el estado CanExecute . Debe llamar al método RaiseCanExecuteChanged en DelegateCommand siempre que detecte una condición que cambie el estado CanExecute del comando. Esto señala el control enlazado para actualizar el estado CanExecute .