WPF:CanExecute始终被禁用

时间:2015-03-07 01:11:42

标签: wpf data-binding delegatecommand

我有一个TextBox供用户输入字符串,并且"添加"按钮用值执行某些任务。我在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并将其更改为&#34; if&#34;检查动作方法。但是这一次,我实际上必须让它工作并将按钮变成灰色的&#34;正确的&#34;方式。

非常感谢任何见解。提前谢谢。

更新

我已将RaiseCanExecuteChanged添加到BuildEntryText属性的set部分。现在按钮开始禁用,并在首次输入文本时启用。但是,即使删除了文本或添加功能清除了该框,它仍会保持启用状态。

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

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

2 个答案:

答案 0 :(得分:0)

您的委托命令需要重新查询以检查命令是否可以执行。委托命令定义在UI线程上引发的名为CanExecuteChanged的事件,以使每个调用控件重新查询以检查命令是否可以执行< / p>

这就是Delegate Command的样子(你的也可能类似)

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" />

答案 1 :(得分:0)

我发现这是一个由两部分组成的问题,而且我的DelegateCommand实际上并不存在问题(至少,并非完全如此)。

1)我需要调用RaiseCanExecuteChanged,正如Rachel建议的那样,或者用户界面不会刷新控件的IsEnabled属性。

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

<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;
    }
}