WPF-Prism CanExecute方法不被调用

问题描述:

我使用两个文本框(用户名和密码)和一个登录按钮来编写一个简单的登录用户控件。我希望仅在填写用户名和密码字段时启用登录按钮。我正在使用Prism和MVVM。 LoginViewModel包含一个名为LoginCommand的属性,该属性绑定到Login按钮。我在我的ViewModel中有一个CanLoginExecute()方法,但它只会在应用程序启动时触发,然后再不会。所以登录按钮从未启用。我错过了什么?WPF-Prism CanExecute方法不被调用

这里是我的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 
} 
+0

什么是CMND:Click.Command =,它说的是棱镜具体。我通常会做

+0

是,CMND:Click.Command =是棱镜具体: 的xmlns:CMND = “CLR-名称空间:Microsoft.Practices.Composite.Presentation.Commands;装配= Microsoft.Practices.Composite.Presentation” 由于我使用棱镜的DelegateCommand,我认为这将是兼容的命令绑定机制。我也尝试过直接Command =“{Binding LoginCommand}” - 它的工作原理完全相同。 – Naresh 2010-03-15 20:59:17

这是最有可能的是,绑定的控件是永远不会要求该CanExecute状态一次。只要您检测到更改命令的CanExecute状态的条件,就需要在DelegateCommand上调用RaiseCanExecuteChanged方法。这表示绑定控件更新CanExecute状态。

+0

RaiseCanExecuteChanged就像一个魅力!感谢olli – Naresh 2010-03-15 21:09:40

+18

只是为了记录(这发生在我身上),我没有找到'RaiseCanExecuteChanged'方法,因为我使用的是ICommand接口。这个方法在DelegateCommand实现中定义,所以我需要对它进行转换。 – alf 2011-10-03 15:16:47

代码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(); 
     } 
    }