WPF-Prism CanExecute 方法未被调用
我正在编写一个简单的登录用户控件,其中包含两个文本框(用户名和密码)和一个登录按钮。我希望仅在填写用户名和密码字段时启用登录按钮。我正在使用 Prism 和 MVVM。 LoginViewModel 包含一个名为 LoginCommand 的属性,该属性绑定到登录按钮。我的 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
}
I am coding a simple login UserControl with two TextBoxes (Username and Password) and a Login button. I want the Login button to be enabled only when the username and password fields are filled in. I am using Prism and MVVM. The LoginViewModel contains a property called LoginCommand that is bound to the Login button. I have a CanLoginExecute() method in my ViewModel but it fires only when the application comes up and then never again. So the Login button is never enabled. What am I missing?
Here's my 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}" />
Here's my 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
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
绑定控件很可能不再请求 CanExecute 状态。每当您检测到更改命令的 CanExecute 状态的条件时,您都需要调用 DelegateCommand 上的 RaiseCanExecuteChanged 方法。这向绑定控件发出信号以更新 CanExecute 状态。
It is most likely that the bound control is never asking for the CanExecute state again. You need to call the RaiseCanExecuteChanged method on the DelegateCommand whenever you detect a condition that changes the command's CanExecute state. This signals the bound control to update the CanExecute state.
从 Prism6 开始,
DelegateCommand
可以“观察”您的属性。意味着每次您的属性发生更改时都会调用 CanExecute-Method。好处是您可以摆脱 Propertysetter 中的RaiseCanExecuteChanged
。如果您想观察更多属性,您还可以链式调用该方法:此外,如果您只想根据布尔属性的状态调用 DelegateCommand,您可以使用
.ObservesCanExecute(()=> BoolProp)< /code>
您不再需要
this.CanLoginExecute
。Starting with Prism6 the
DelegateCommand
can "observe" your propertys. Means everytime your property is changing the CanExecute-Method is called. The good thing is you get rid ofRaiseCanExecuteChanged
in the Propertysetter. You can also chain-call that method if you want to observe more properties:Furthermore if you just want your DelegateCommand be called depending on the state of a boolean property you can use
.ObservesCanExecute(()=> BoolProp)
You dont need
this.CanLoginExecute
anymore.RaiseCanExecuteChanged 的代码:
Code for RaiseCanExecuteChanged:
这是 Prism 的一个小解决方法(使用 Prism.Core 7.1.0.431 进行测试):
Here's a little workaround for Prism (tested with Prism.Core 7.1.0.431):