WPF-Prism CanExecute method not being called

Naresh picture Naresh · Mar 15, 2010 · Viewed 25.3k times · Source

I am coding a simple login UserControl with two TextBoxes (Username and Password) and a Login button. I want the Login button to be enabled only when the username and password fields are filled in. I am using Prism and MVVM. The LoginViewModel contains a property called LoginCommand that is bound to the Login button. I have a CanLoginExecute() method in my ViewModel but it fires only when the application comes up and then never again. So the Login button is never enabled. What am I missing?

Here's my 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}" />

Here's my 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
}

Answer

olli-MSFT picture olli-MSFT · Mar 15, 2010

It is most likely that the bound control is never asking for the CanExecute state again. You need to call the RaiseCanExecuteChanged method on the DelegateCommand whenever you detect a condition that changes the command's CanExecute state. This signals the bound control to update the CanExecute state.