WPF:始终禁用 CanExecute

WPF: CanExecute is Always Disabled

我有一个 TextBox 供用户输入字符串,还有一个 "Add" 按钮用于使用该值执行一些任务。我向 DelegateCommand 添加了一个 CanExecute 方法,以便按钮仅在框中有文本时才起作用。

但是,它始终处于禁用状态 - 即使条件为真。在框中键入不会启用该按钮。

<TextBox Text="{Binding BuildEntryText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button Command="{Binding AddBuildCommand}" Content="Add" />

this.AddBuildCommand = new DelegateCommand(() => this.AddBuild(), () => this.CanAddBuild());

private bool CanAddBuild()
{
    if (this.BuildEntryText != null)
    {
        return true;
    }
    else
    {
        return false;
    }
}

我以前遇到过这种情况(并不总是使用相同类型的控件),通常我会删除 CanExecute 并将其更改为操作方法中的 "if" 检查。不过这一次,我实际上必须让它工作并将按钮变灰 "proper"。

如有任何见解,我们将不胜感激。提前致谢。

更新:

我已将 RaiseCanExecuteChanged 添加到 BuildEntryText 的设置部分 属性。现在按钮开始禁用并在首次键入文本时变为启用。但是,即使在删除文本或通过添加功能清除框后,它仍保持启用状态。

public string BuildEntryText
{
    get
    {
        return this.buildEntryText;
    }

    set
    {
        this.SetProperty<string>(ref this.buildEntryText, value);
        this.AddBuildCommand.RaiseCanExecuteChanged();
    }
}

您的委托命令需要重新查询以检查命令是否可以执行。委托命令定义了名为 CanExecuteChanged 的事件,该事件在 UI 线程上引发以导致每个调用控件重新查询以进行检查如果命令可以执行

这就是委托命令的样子(你的也可能类似)

public class DelegateCommand<T> : System.Windows.Input.ICommand
{
   private readonly Predicate<T> _canExecute;
   private readonly Action<T> _execute;

     public DelegateCommand(Action<T> execute)
    : this(execute, null)
     {
     }

    public DelegateCommand(Action<T> execute, Predicate<T> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        if (_canExecute == null)
            return true;

        return _canExecute((parameter == null) ? default(T) :(T)Convert.ChangeType(parameter, typeof(T)));
    }

    public void Execute(object parameter)
    {
        _execute((parameter == null) ? default(T) : (T)Convert.ChangeType(parameter, typeof(T)));
    }

    public event EventHandler CanExecuteChanged;
    public void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
            CanExecuteChanged(this, EventArgs.Empty);
    }
}

您正在将其绑定到 TextBox

的文本命令

这是一个示例 ViewModel.cs

public class ViewModel
{
    private readonly DelegateCommand<string> MyButtonCommand;

    public ViewModel()
    {
        MyButtonCommand= new DelegateCommand<string>(
            (s) => { MessageBox.Show("Command Executed")}, //Execute
            (s) => { return !string.IsNullOrEmpty(_input); } //CanExecute
            );
    }

    public DelegateCommand<string> AddBuildCommand
    {
        get { return MyButtonCommand; }
    }

    private string _input;
    public string BuildEntryText
    {
        get { return _input; }
        set
        {
            _input = value;
            MyButtonCommand.RaiseCanExecuteChanged();
        }
    }
}  

并且在你的XAML

 <TextBox Text="{Binding BuildEntryText,   UpdateSourceTrigger=PropertyChanged}" />
<Button Command="{Binding AddBuildCommand}" Content="Add" />

我发现这是一个由两部分组成的问题,实际上这不是我的 DelegateCommand 的问题(至少,不完全是)。

1) 我需要按照 Rachel 的建议调用 RaiseCanExecuteChanged,否则 UI 不会刷新控件的 IsEnabled 属性。

2) 我需要添加一个附加条件来检查字符串的长度,而不是只检查它是否为空。显然,一个空的 TextBox 开始时为 null,但是如果您添加字符然后删除它们,它不会再次变回 null。 它是一个长度为 0 的字符串。

<TextBox Text="{Binding BuildEntryText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button Command="{Binding AddBuildCommand}" Content="Add" />

public DelegateCommand AddBuildCommand { get; private set; }

this.AddBuildCommand = new DelegateCommand(() => this.AddBuild(), () => this.CanAddBuild());

public string BuildEntryText
{
    get
    {
        return this.buildEntryText;
    }

    set
    {
        this.SetProperty<string>(ref this.buildEntryText, value);

        // PART 1:
        this.AddBuildCommand.RaiseCanExecuteChanged();
    }
}

private bool CanAddBuild()
{
    // PART 2:
    if (this.BuildEntryText != null && this.BuildEntryText.Length > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}