rookie
rookie

Reputation: 2923

Make Command's CanExecute depend on other field's value

I'm working on a small WPF MVVM application. In essence, the user browses for a file, then clicks "Execute" to run some code on the file.

In my view model class, I've bound the two button clicks ("Browse" and "Execute") to an ICommand.

internal class DelegateCommand : ICommand
{
    private readonly Action _action;

    public DelegateCommand(Action action)
    {
        _action = action;
    }

    public void Execute(object parameter)
    {
        _action();
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;
}

internal class Presenter : INotifyPropertyChanged // VM class
{
    private string filePath;

    public string FilePath
    {
        get { return filePath; }
        set 
        { 
            filePath = value;
            RaisePropertyChangedEvent("FilePath");
        }
    }

    public ICommand ExecuteCommand
    { 
        // returns a DelegateCommand
    }

    public ICommand BrowseCommand
    { 
        // how to enable/disable button based on whether or not a file has been selected?
    }
}

Here, CanExecute always returns true. What I'd like to have happen, though, is for CanExecute to be tied to whether or not a file has been selected (i.e. to whether or not FilePath.Length > 0) and then link the button's status (enabled/disabled) to that. What's the best way to do this without adding an IsFileSelected observable property to Presenter?

Upvotes: 1

Views: 669

Answers (1)

brunnerh
brunnerh

Reputation: 185445

Usually i have a base class for ICommand instances that takes a delegate for both its Execute and CanExecute methods. That being the case you can capture things in scope via closures. e.g. something along those lines:

private readonly DelegateCommand _executeCommand;
public DelegateCommand ExecuteCommand { /* get only */ }

public Presenter()
{
    _excuteCommand = new DelegateCommand
    (
        () => /* execute code here */,
        () => FilePath != null /* this is can-execute */
    );
}

public string FilePath
{
    get { return filePath; }
    set 
    { 
        filePath = value;
        RaisePropertyChangedEvent("FilePath");
        ExecuteCommand.OnCanExecuteChanged(); // So the bound control updates
    }
}

Upvotes: 3

Related Questions