WPF Commands

Introduction to Commands

In Windows Presentation Foundation (WPF), commands provide a way to abstract user input into actionable operations. They are a core part of the MVVM (Model-View-ViewModel) pattern, promoting separation of concerns and testability. Commands allow you to decouple the user interface element that triggers an action from the logic that performs the action.

Key benefits of using commands include:

  • Decoupling: Separates UI from business logic.
  • Reusability: Commands can be reused across different UI elements.
  • Enabling/Disabling: Commands can dynamically manage their enabled/disabled state based on application context.
  • Testability: Easier to unit test logic independent of the UI.

The ICommand Interface

The foundation of WPF commands is the System.Windows.Input.ICommand interface. This interface defines two essential methods and one event:

  • CanExecute(object parameter): Returns a boolean indicating whether the command can currently be executed.
  • Execute(object parameter): Performs the command's action.
  • CanExecuteChanged: An event that is raised when the state of the command (whether it can be executed) changes.

Implementing ICommand

You can implement ICommand yourself or use the built-in implementations provided by WPF.


public interface ICommand
{
    bool CanExecute(object parameter);
    void Execute(object parameter);
    event EventHandler CanExecuteChanged;
}
                

Built-in Command Implementations

WPF provides several useful built-in command implementations:

RoutedCommand

RoutedCommands are commands that are routed through the element tree. They are often used when the command logic needs to interact with elements in the UI tree. They are typically associated with a gesture (like a key combination) and can be handled by any element along the route.

RoutedUICommand

Similar to RoutedCommand, but specifically designed for common UI operations like Copy, Cut, Paste, Save, etc. These commands often have pre-defined gestures and display text.

DelegateCommand (Not built-in, but common pattern)

While not directly part of the WPF framework, DelegateCommand is a very common pattern used in MVVM scenarios, especially within ViewModel implementations. It wraps a delegate (or lambda expression) for the Execute and CanExecute logic, often using a callback for CanExecuteChanged.

The CommandManager class plays a crucial role in coordinating command execution and managing the CanExecuteChanged event for RoutedCommands.

Using Commands in XAML

Commands are typically bound to UI elements using the Command property.

Binding to a Button


<Button Content="Save" Command="{Binding SaveCommand}" />
                

Binding to a MenuItem


<MenuItem Header="Edit">
    <MenuItem Header="Copy" Command="{Binding CopyCommand}" />
    <MenuItem Header="Paste" Command="{Binding PasteCommand}" />
</MenuItem>
                

Command Parameters

You can pass parameters to commands using the CommandParameter property.


<Button Content="Delete Item" Command="{Binding DeleteCommand}" CommandParameter="{Binding SelectedItem}" />
                

ViewModel Implementation (MVVM Pattern)

In MVVM, commands are typically defined in the ViewModel. Here's an example using a simplified DelegateCommand (often provided by libraries like MVVM Light or Prism, or implemented manually).

Manual DelegateCommand Implementation


public class DelegateCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Predicate<object> _canExecute;

    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<object> execute, Predicate<object> canExecute = null)
    {
        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        _canExecute = canExecute;
    }

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

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

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}
                

ViewModel Example


public class MyViewModel : INotifyPropertyChanged
{
    private string _inputText;
    public string InputText
    {
        get { return _inputText; }
        set { _inputText = value; OnPropertyChanged(nameof(InputText)); }
    }

    public DelegateCommand SubmitCommand { get; private set; }
    public DelegateCommand ClearCommand { get; private set; }

    public MyViewModel()
    {
        SubmitCommand = new DelegateCommand(ExecuteSubmit, CanExecuteSubmit);
        ClearCommand = new DelegateCommand(ExecuteClear);
    }

    private void ExecuteSubmit(object parameter)
    {
        // Perform submission logic with InputText
        MessageBox.Show($"Submitted: {InputText}");
    }

    private bool CanExecuteSubmit(object parameter)
    {
        // Enable submit only if InputText is not empty
        return !string.IsNullOrWhiteSpace(InputText);
    }

    private void ExecuteClear(object parameter)
    {
        InputText = string.Empty;
        // Notify the submit command that its CanExecute state might have changed
        SubmitCommand.RaiseCanExecuteChanged();
    }

    // INotifyPropertyChanged implementation...
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
                
When the bound property (e.g., InputText) changes, you must ensure that the CanExecute status of dependent commands (e.g., SubmitCommand) is re-evaluated. Calling RaiseCanExecuteChanged() on the command will trigger WPF to re-query its CanExecute state.

Command Binding

CommandBinding objects connect a command to a handler in the code-behind of a UI element. This is more commonly used with RoutedCommands and in code-behind scenarios rather than pure MVVM.

XAML


<Window.CommandBindings>
    <CommandBinding Command="ApplicationCommands.Save" Executed="SaveCommand_Executed" CanExecute="SaveCommand_CanExecute" />
</Window.CommandBindings>
<Button Command="ApplicationCommands.Save" Content="Save" />
                

C# Code-Behind


private void SaveCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = IsDataDirty; // Assume IsDataDirty is a property
}

private void SaveCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
    // Save logic
}
                

Summary

WPF Commands are a powerful mechanism for handling user interactions in a structured and maintainable way. They are essential for building responsive and testable applications, especially when following the MVVM pattern. By understanding the ICommand interface and leveraging built-in or custom command implementations, you can significantly improve the architecture of your WPF applications.