首页 文章

WPF-Prism CanExecute方法未被调用

提问于
浏览
20

我正在使用两个TextBox(用户名和密码)和一个Login按钮编写一个简单的登录UserControl . 我希望只有在填写用户名和密码字段时才启用“登录”按钮 . 我使用的是Prism和MVVM . LoginViewModel包含一个名为LoginCommand的属性,该属性绑定到Login按钮 . 我的ViewModel中有一个CanLoginExecute()方法,但它只在应用程序出现时才会触发,然后再也不会触发 . 因此,从不启用“登录”按钮 . 我错过了什么?

这是我的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 回答

  • 1

    绑定控件很可能永远不再要求CanExecute状态 . 每当检测到更改命令的CanExecute状态的条件时,您需要在DelegateCommand上调用 RaiseCanExecuteChanged 方法 . 这表示绑定控件更新CanExecute状态 .

  • 8

    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();
            }
        }
    
  • 4

    从Prism6开始 DelegateCommand 可以"observe"你的属性 . 意味着每次你的 property 改变时,都会调用CanExecute-Method . 好处是你摆脱了Propertysetter中的 RaiseCanExecuteChanged . 如果要观察更多属性,还可以对该方法进行链式调用:

    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 了 .

  • 42

    这是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; }
        }
    }
    

相关问题