【问题标题】:WPF-Prism CanExecute method not being called未调用 WPF-Prism CanExecute 方法
【发布时间】:2011-01-27 13:05:36
【问题描述】:

我正在编写一个简单的登录用户控件,其中包含两个文本框(用户名和密码)和一个登录按钮。我希望仅在填写用户名和密码字段时才启用登录按钮。我使用的是 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}" />

这是我的视图模型

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
}

【问题讨论】:

  • 什么是 cmnd:Click.Command= ,是 Prism 特有的。我通常这样做
  • 是的,cmnd:Click.Command= 是特定于棱镜的:xmlns:cmnd="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"我正在使用 Prism 的 DelegateCommand,我认为这将是兼容的命令绑定机制。我也尝试过直接 Command="{Binding LoginCommand}" - 它的工作原理完全相同。

标签: wpf prism command


【解决方案1】:

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

【讨论】:

  • 只是为了记录(这发生在我身上),我没有找到 RaiseCanExecuteChanged 方法,因为我使用的是 ICommand 接口。这个方法是在 DelegateCommand 实现中定义的,所以我需要转换它。
【解决方案2】:

从 Prism6 开始,DelegateCommand 可以“观察”您的属性。意味着每次您的属性发生变化时都会调用 CanExecute-Method。好消息是您摆脱了 Propertysetter 中的RaiseCanExecuteChanged。如果您想观察更多属性,也可以链式调用该方法:

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

此外,如果您只想根据布尔属性的状态调用您的 DelegateCommand,您可以使用 .ObservesCanExecute(()=&gt; BoolProp)

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

你不再需要this.CanLoginExecute了。

【讨论】:

    【解决方案3】:

    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】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-09-14
        • 1970-01-01
        • 2019-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-12
        • 1970-01-01
        相关资源
        最近更新 更多