[英]How to disable a button if textbox and passwordbox is blank in wpf?
I basically used a Model
's (UserAccount) Property
from my ViewModel
(CreateAccountViewModel) to bind to my View
, and call to my Command
(CreateAccountCommand).我基本上使用我的ViewModel
(CreateAccountViewModel) 中的Model
的 (UserAccount) Property
绑定到我的View
,并调用我的Command
(CreateAccountCommand)。
My Model
(UserAccount):我的Model
(用户帐户):
public class UserAccount : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _id;
private string _username;
private string _password;
private DateTime _dateTime;
public int Id
{
get { return _id; }
set { _id = value; OnPropertyChanged(nameof(Id)); }
}
public string Username
{
get { return _username; }
set { _username = value; OnPropertyChanged(nameof(Username)); }
}
public string Password
{
get { return _password; }
set { _password = value; OnPropertyChanged(nameof(Password)); }
}
public DateTime DateCreated
{
get { return _dateTime; }
set { _dateTime = value; OnPropertyChanged(nameof(DateCreated)); }
}
public virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
My ViewModel
(CreateAccountViewModel):我的ViewModel
(CreateAccountViewModel):
public class CreateAccountViewModel: ViewModelBase
{
private UserAccount _userAccount;
public UserAccount CurrentUserAccount
{
get { return _userAccount; }
set { _userAccount = value; OnPropertyChanged(nameof(CurrentUserAccount)); }
}
public ICommand CreateAccountCommand{ get; }
public CreateAccountViewModel()
{
CreateAccountCommand= new CreateAccountCommand(this, Test);
CurrentUserAccount = new UserAccount();
}
public void Test()
{
MessageBox.Show("Random Message");
//I'm going to put my Create functionality here
}
}
My View
(CreateAccountView):我的View
(CreateAccountView):
<!--The TextBox for username-->
<TextBox Grid.Column="1"
Margin="10,0,0,0"
Text="{Binding Path=CurrentUserAccount.Username, UpdateSourceTrigger=PropertyChanged}" />
<!--The PasswordBox for password-->
<components:BindablePasswordBox Grid.Column="1"
Margin="10,0,0,0"
Password="{Binding Path=CurrentUserAccount.Password, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Grid.ColumnSpan="2" />
<!--The Create user button-->
<Button Grid.Row="2"
Margin="0,20,0,0"
HorizontalAlignment="Center"
Command="{Binding CreateAccountCommand}"
Content="Create Account" />
My Command
(CreateAccountCommand):我的Command
(CreateAccountCommand):
public class CreateAccountCommand: ICommand
{
private readonly CreateAccountViewModel _viewModel;
private readonly Action RunCommand;
public CreateAccountCommand(CreateAccountViewModel viewModel , Action runCommand)
{
_viewModel = viewModel;
_viewModel.PropertyChanged += ViewModel_PropertyChanged;
RunCommand = runCommand;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
//This is supposed to check whether the Username textbox and Password passwordbox is blank (if both of them are blank, the button should be disabled, else disabled
return !string.IsNullOrEmpty(_viewModel.CurrentUserAccount.Username) && !string.IsNullOrEmpty(_viewModel.CurrentUserAccount.Password);
}
public void Execute(object parameter)
{
RunCommand();
}
private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
CanExecuteChanged?.Invoke(this, new EventArgs());
}
}
My PasswordBox
is bindable because I created a custom PasswordBox
with DependencyProperty
:我的PasswordBox
是可绑定的,因为我使用DependencyProperty
创建了一个自定义PasswordBox
:
public partial class BindablePasswordBox : UserControl
{
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox),
new PropertyMetadata(string.Empty));
public string Password
{
get { return (string)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
public BindablePasswordBox()
{
InitializeComponent();
}
//This method will notify us, whenever a password in our passwordBox changes
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
Password = passwordBox.Password; //sets the value of the DependencyProperty (PasswordProperty)
}
}
My problem here, is that, the button in my View
does not change enable/disable even if I set my command's CanExecute
to do so.我的问题是,即使我将命令的CanExecute
设置为这样做,我的View
中的按钮也不会更改启用/禁用。 Am I missing something obvious here?我在这里遗漏了一些明显的东西吗? I really have to ask because I've been stuck here since yesterday.我真的要问,因为我从昨天开始就被困在这里了。 (My Main goal here is to disable the Create Account
button if the Textbox
and PasswordBox
have no input. Any solutions are okay) (我的主要目标是在Textbox
和PasswordBox
没有输入时禁用Create Account
按钮。任何解决方案都可以)
Lets do a small refactoring.让我们做一个小的重构。
CallerMemberNameAttribute
(see here how) to have shorter property setters in vm;使用CallerMemberNameAttribute
(见这里如何)在 vm 中有更短的属性设置器;ICommand
implementation and use it for all commands, see DelegateCommand ;编写一次可重用的ICommand
实现并将其用于所有命令,请参阅DelegateCommand ;CanExecuteChanged
in vm when you change one of command canExecuted
condition;当您更改命令canExecuted
条件之一时,在 vm 中上升命令CanExecuteChanged
;UserAccount
needs notifications (you have done it in the edit), if it's a model, then you need an extra vm to act as a wrapper, otherwise you wouldn't be able to catch changes done by the bound controls; UserAccount
需要通知(您已在编辑中完成),如果它是 model,那么您需要一个额外的 vm 来充当包装器,否则您将无法捕获绑定控件所做的更改;UserAccount
are part of command canExecuted
, you need to monitor for them.由于UserAccount
的属性是命令canExecuted
的一部分,因此您需要监视它们。With all changes your button using the command should be property enabled/disabled.通过所有更改,您使用命令的按钮应启用/禁用属性。
Below is pseudo-code (can contain mistakes):以下是伪代码(可能包含错误):
public class CreateAccountViewModel: ViewModelBase
{
UserAccount _userAccount;
public UserAccount CurrentUserAccount
{
get => _userAccount;
set
{
// unsubscribe
if(_userAccount != null)
_userAccount -= UserAccount_PropertyChanged;
_userAccount = value;
// subscribe
if(_userAccount != null)
_userAccount += UserAccount_PropertyChanged;
// notifications
OnPropertyChanged(); // shorter syntax with CallerMemberNameAttribute
CreateAccountCommand.RaiseCanExecuteChanged();
}
}
public ICommand CreateAccountCommand { get; }
public CreateAccountViewModel()
{
CurrentUserAccount = new UserAccount();
CreateAccountCommand = new DelegateCommand(Test,
o => !string.IsNullOrEmpty(CurrentUserAccount.Username) && !string.IsNullOrEmpty(CurrentUserAccount.Password));
}
void Test(object parameter)
{
MessageBox.Show("Random Message");
//I'm going to put my Create functionality here
}
void UserAccount_PropertyChanged(object sender, NotifyPropertyChangedEventArgs e) =>
CreateAccountCommand.RaiseCanExecuteChanged(); // rise always of check for specific properties changes
}
The CreateAccountCommand
hooks up en event handler to the view model's PropertyChanged
but there is no such event raised when you set the Username
and Password
properties of the UserAccount
object. CreateAccountCommand
将事件处理程序连接到视图模型的PropertyChanged
,但是当您设置UserAccount
object 的Username
名和Password
属性时,不会引发此类事件。
Either implement INotifyPropertyChanged
in UserAccount
or bind to wrapper properties of the CreateAccountViewModel
:在UserAccount
中实现INotifyPropertyChanged
或绑定到CreateAccountViewModel
的包装器属性:
public string Username
{
get { return _userAccount?.Username; }
set
{
if (_userAccount != null)
_userAccount.Username = value;
OnPropertyChanged();
}
}
If you decide to implement INotifyPropertyChanged
in UserAccount
, you still need to notify the command when the properties have been updated.如果您决定在UserAccount
中实现INotifyPropertyChanged
,您仍然需要在属性更新时通知该命令。
Since your CurrentUserAccount
property may be set to a new value dynamically, you should remove and add the event handler dynamically:由于您的CurrentUserAccount
属性可能会动态设置为新值,因此您应该动态删除和添加事件处理程序:
private UserAccount _userAccount;
public UserAccount CurrentUserAccount
{
get { return _userAccount; }
set
{
if (_userAccount != null)
_userAccount.PropertyChanged -= OnUserAccountPropertyChanged;
_userAccount = value;
if (_userAccount != null)
_userAccount.PropertyChanged += OnUserAccountPropertyChanged;
OnPropertyChanged(nameof(CurrentUserAccount));
}
}
private void OnUserAccountPropertyChanged(object sender, PropertyChangedEventArgs e) =>
OnPropertyChanged(null);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.