7. Commands

Commands in WPF

Introduction

Commands are an integral part of Windows Presentation Foundation (WPF) applications, used to decouple the objects that invoke actions from the objects that perform these actions. Understanding the command pattern and the Model-View-ViewModel (MVVM) pattern are key to effectively implementing commands in WPF.

Command Pattern

The Command Pattern is a design pattern that is used to encapsulate a request as an object, thus allowing users to parameterize clients with queues, requests, and operations. This pattern simplifies complex projects by enabling different elements (buttons, shortcuts, menu items, etc.) to call the same function.

Example:

public class Invoker
{
    private ICommand _command;

    public void SetCommand(ICommand command)
    {
        this._command = command;
    }

    public void ExecuteCommand()
    {
        _command.Execute();
    }
}

MVVM Pattern

The Model-View-ViewModel (MVVM) Pattern is a design pattern that separates the user interface (view) from the business logic, which should be encapsulated within view models. Each view should have a corresponding view model.

Example:

public class MainViewModel : INotifyPropertyChanged
{
    private string _text;

    public string Text
    {
        get { return _text; }
        set
        {
            _text = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Command Execution

Commands in WPF have two methods - CanExecute and Execute. The CanExecute method runs continuously without impacting performance, and its state (true or false) can be used to enable or disable the Execute method.

Example:

public class RelayCommand : ICommand
{
    private Action _execute;
    private Func<bool> _canExecute;

    public RelayCommand(Action execute, Func<bool> canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute();
    }

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

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}

RelayCommand

RelayCommand is a class that derives from ICommand. Each command can have its own class, or a single class can be created for all commands, depending on the situation.

Example:

public class RelayCommand : ICommand
{
    private Action<object> execute;
    private Predicate<object> canExecute;

    public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
    {
        this.execute = execute;
        this.canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return canExecute == null ? true : canExecute(parameter);
    }

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

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}

Input Bindings

Button.InputBindings is used to use other events apart from the click event. The name of the event used in the gesture is written in the command.

Example:

<Button Content="Button">
    <Button.InputBindings>
        <MouseBinding MouseAction="LeftClick" Command="{Binding ClickCommand}"/>
    </Button.InputBindings>
</Button>

This way, the command will be executed when the left mouse button is clicked.

Reference

The content in this document is based on the original notes provided in Azerbaijani. For further details, you can refer to the original document using the following link:

Original Note - Azerbaijani Version