You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.19 05:54:00