WPF如何在TextBox和PasswordBox为空时禁用Button?现有实现不生效求解
问题原因
你当前按钮状态不更新的核心原因是:CreateAccountCommand只监听了CreateAccountViewModel级别的属性变更事件,但你做非空判断的Username、Password是嵌套对象CurrentUserAccount的属性,这两个属性变更时只会触发UserAccount自身的PropertyChanged事件,不会向上冒泡到ViewModel层,因此Command收不到变更通知,不会重新执行CanExecute逻辑,按钮状态自然不会更新。
其次还有一个隐藏问题是你自定义的BindablePasswordBox没有实现完整的双向绑定逻辑,仅支持从界面输入同步到ViewModel,不支持ViewModel值变更同步回界面。
解决方案
步骤1:调整ViewModel监听嵌套对象属性变更
修改CreateAccountViewModel代码,在CurrentUserAccount赋值时订阅其内部属性变更事件,当用户名/密码变更时主动通知Command刷新可执行状态:
public class CreateAccountViewModel: ViewModelBase { private UserAccount _userAccount; public UserAccount CurrentUserAccount { get => _userAccount; set { // 先取消旧实例的事件订阅,避免内存泄漏 if (_userAccount != null) _userAccount.PropertyChanged -= OnUserAccountPropertyChanged; _userAccount = value; // 给新实例订阅属性变更事件 if (_userAccount != null) _userAccount.PropertyChanged += OnUserAccountPropertyChanged; OnPropertyChanged(nameof(CurrentUserAccount)); } } public ICommand CreateAccountCommand{ get; } public CreateAccountViewModel() { CreateAccountCommand= new CreateAccountCommand(this, Test); CurrentUserAccount = new UserAccount(); } public void Test() { MessageBox.Show("Random Message"); //创建账户逻辑将写在此处 } // 监听UserAccount内部属性变更 private void OnUserAccountPropertyChanged(object sender, PropertyChangedEventArgs e) { // 仅当用户名或密码变更时,刷新Command可执行状态 if (e.PropertyName is nameof(UserAccount.Username) or nameof(UserAccount.Password)) { (CreateAccountCommand as CreateAccountCommand)?.RaiseCanExecuteChanged(); } } }
步骤2:给Command添加手动触发CanExecute变更的方法
修改CreateAccountCommand代码,新增公开的RaiseCanExecuteChanged方法供外部调用:
public class CreateAccountCommand: ICommand { private readonly CreateAccountViewModel _viewModel; private readonly Action RunCommand; public CreateAccountCommand(CreateAccountViewModel viewModel , Action runCommand) { _viewModel = viewModel; RunCommand = runCommand; } public event EventHandler CanExecuteChanged; public bool CanExecute(object parameter) { return !string.IsNullOrEmpty(_viewModel.CurrentUserAccount.Username) && !string.IsNullOrEmpty(_viewModel.CurrentUserAccount.Password); } public void Execute(object parameter) { RunCommand(); } // 新增:手动触发CanExecute变更通知 public void RaiseCanExecuteChanged() { CanExecuteChanged?.Invoke(this, EventArgs.Empty); } }
原Command中订阅ViewModel的PropertyChanged的逻辑已经不需要,可以直接删除。
步骤3(可选但推荐):修复BindablePasswordBox双向绑定逻辑
给Password依赖属性添加属性变更回调,实现ViewModel值到界面的同步:
public partial class BindablePasswordBox : UserControl { public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox), new PropertyMetadata(string.Empty, OnPasswordPropertyChanged)); public string Password { get => (string)GetValue(PasswordProperty); set => SetValue(PasswordProperty, value); } public BindablePasswordBox() { InitializeComponent(); } private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e) { Password = passwordBox.Password; } // 新增:当ViewModel侧Password变更时,同步更新界面PasswordBox的显示 private static void OnPasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is BindablePasswordBox bindablePasswordBox) { bindablePasswordBox.passwordBox.Password = e.NewValue as string; } } }
修改完成后,按钮就会根据用户名、密码的输入状态自动切换启用/禁用状态。
内容的提问来源于stack exchange,提问作者jd0x0021
相关产品推荐
相关产品推荐

