为什么不能';t我的命令启用按钮

本文关键字:我的 命令 启用 按钮 不能 为什么 | 更新日期: 2023-09-27 18:20:54

我正在学习使用Prism中的DelgateCommand。。。。

在我的UI中,我有我的用户名文本框和密码框:

<TextBox Name="_UserNameTextBox" Text="{Binding UserName, Mode=TwoWay}" />
<PasswordBox Name="_PasswordBox"></PasswordBox>

还有我的登录按钮:

<Button Name="button1" Command="{Binding LoginCommand, Mode=TwoWay}" CommandTarget="{Binding ElementName=_UserNameTextBox, Path=Text}">Login</Button>

然后我的ViewModel我有:

    string _UserName = string.Empty;
    public string UserName
    {
        get
        {
            return _UserName;
        }
        set
        {
            if (value != _UserName)
            {
                _UserName = value;
                RaisePropertyChanged("UserName");
            }
        }
    }
    //For reference the password
    PasswordBox _PasswordBox { get; set; }

    public DelegateCommand<string> LoginCommand { get; set; }
    public LoginViewModel(PasswordBox passwordBox)
    {
        _PasswordBox = passwordBox;
        LoginCommand = new DelegateCommand<string>(
            (
                //Execute
                (str) =>
                {
                    Login(_PasswordBox.Password);
                }
            ),
                //CanExecute Delgate
                (usr) =>
                {
                    if (string.IsNullOrEmpty(usr) || string.IsNullOrEmpty(_PasswordBox.Password))
                        return false;
                    return true;
                }
            );
    }

我可以看到我的UserName绑定正确,并且我确实在ViewModel构造函数中传递了我的PasswordBox作为引用。当我执行应用程序时,按钮被禁用,所以我知道它绑定到了命令上。

但我从来没有看到我写的CanExecute delgate在我输入UserName和PasswordBox后被检查。。。。并且从未启用。。。

那么我做错了什么?

编辑:

=====

所以最终结果是…这个?

string _UserName = string.Empty;
        public string UserName
        {
            get
            {
                return _UserName;
            }
            set
            {
                if (value != _UserName)
                {
                    _UserName = value;
                    RaisePropertyChanged("UserName");
                    LoginCommand.RaiseCanExecuteChanged();
                }
            }
        }
        //For reference the password
        PasswordBox _PasswordBox { get; set; }

        public DelegateCommand<string> LoginCommand { get; set; }
        public LoginViewModel(PasswordBox passwordBox)
        {
            _PasswordBox = passwordBox;
            _PasswordBox.PasswordChanged += delegate(object sender, System.Windows.RoutedEventArgs e)
            {
                LoginCommand.RaiseCanExecuteChanged();
            };
            LoginCommand = new DelegateCommand<string>(
                (
                    (str) =>
                    {
                        Login(_PasswordBox.Password);
                    }
                ),
                    (usr) =>
                    {
                        if (string.IsNullOrEmpty(usr) || string.IsNullOrEmpty(_PasswordBox.Password))                        
                            return false;
                        return true;
                    }
                );
        }

为什么不能';t我的命令启用按钮

一般来说,只要CanExecute返回的影响值发生变化,就必须调用RaiseCanExecuteChanged。在这种特定情况下,每当用户或密码字段的值发生更改时,您都需要调用它。但这非常困难,因为您的ViewModel实现是完全错误的。

以下是您应该做的:

  1. 在ViewModel中公开UsernamePassword属性。您需要显式地实现getter和setter(即它不能是一个自动属性)
  2. 在视图中,将用户名和密码输入字段的内容绑定到这些属性
  3. 在属性设置器中,调用LoginCommand.RaiseCanExecuteChanged

以下是当你这样做时会发生的事情(让我们选择密码框作为示例):

  1. 用户在密码框中键入一个字符
  2. 由于双向绑定,WPF设置LoginViewModel.Password的值
  3. 密码设置程序调用RaiseCanExecuteChanged,这将在您的命令中引发CanExecuteChanged事件
  4. 提交按钮(当您将其绑定到命令时,它已经订阅了该事件)会收到通知
  5. 该按钮调用CanExecute以查看现在是否允许执行该命令
  6. 您的代理运行并返回true,因此按钮会自行激活

您需要绑定Button.CommandParameter(它将被传递给ExecuteCanExecute),如果该绑定发生更改,则据我所知,CanExecute将被重新赋值。

(我认为您混淆了CommandParameterCommandTargetCommandTarget不在命令中使用,它只用于在某个元素上引发命令(这可能与命令路由等相关)