为什么我的命令无法启用按钮?

时间:2012-01-19 19:10:30

标签: c# wpf xaml mvvm prism

我正在学习使用Prism的DelgateCommand ....

在我的用户界面中,我有UserName文本框和PasswordBox:

<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正确绑定,我确实将我的PasswordBox传递给ViewModel构造函数中的referece。当我执行应用程序时,Button被禁用,所以我知道绑定到命令。

但我从来没有看到我写的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;
                    }
                );
        }

2 个答案:

答案 0 :(得分:2)

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

这是你应该做的事情:

  1. 在ViewModel中展示UsernamePassword属性。您需要明确地实现getter和setter(即它不能是自动属性)。
  2. 在您的视图中,将用户名和密码输入字段的内容绑定到这些属性。
  3. 在属性设置器中,调用LoginCommand.RaiseCanExecuteChanged
  4. 以下是执行此操作时会发生的情况(让我们选择密码框作为示例):

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

答案 1 :(得分:1)

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

(我认为您将CommandParameterCommandTarget混淆,CommandTarget未在命令中使用,它仅用于在某个元素上引发命令(可以与命令路由相关,例如