C# > UI Programming > WPF > Command Binding

Simple Command Binding in WPF

This snippet demonstrates a basic implementation of command binding in WPF using ICommand and a RelayCommand helper class. It allows a button in the UI to execute a method in the ViewModel.

ViewModel Implementation (MyViewModel.cs)

This code defines a ViewModel, `MyViewModel`, with an `ICommand` property called `MyCommand`. The `RelayCommand` is a simple helper class that implements the `ICommand` interface. The `ExecuteMyCommand` method is the action that will be executed when the command is invoked, and the `CanExecuteMyCommand` method determines whether the command can be executed. The `Message` property is bound to the UI and updated when the command is executed. It also implements `INotifyPropertyChanged` to notify the UI when properties change.

using System; 
using System.Windows.Input;
using System.ComponentModel;

public class MyViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _message;
    public string Message
    {
        get { return _message; }
        set
        {
            _message = value;
            OnPropertyChanged(nameof(Message));
        }
    }

    public ICommand MyCommand { get; private set; }

    public MyViewModel()
    {
        MyCommand = new RelayCommand(ExecuteMyCommand, CanExecuteMyCommand);
        Message = "Initial Message";
    }

    private void ExecuteMyCommand(object parameter)
    {
        Message = "Command Executed!";
    }

    private bool CanExecuteMyCommand(object parameter)
    {
        return true; // Command can always execute in this example
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

// Simple RelayCommand implementation
public class RelayCommand : ICommand
{
    private Action<object> _execute;
    private Predicate<object> _canExecute;

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

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

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

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

WPF View (MainWindow.xaml)

This XAML code defines the UI for the application. The `DataContext` of the `Window` is set to an instance of `MyViewModel`. The `Button`'s `Command` property is bound to the `MyCommand` property of the ViewModel. The `TextBlock` is bound to the `Message` property, so it will update when the `Message` property in the ViewModel changes. Notice the local namespace definition points to the assembly.

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MyViewModel/>
    </Window.DataContext>
    <Grid>
        <StackPanel>
            <TextBlock Text="{Binding Message}" Margin="10"/>
            <Button Content="Execute Command" Command="{Binding MyCommand}" Margin="10" Width="150"/>
        </StackPanel>
    </Grid>
</Window>

Concepts Behind Command Binding

Command binding decouples the UI (View) from the business logic (ViewModel). The View only knows that a command exists and should be executed when a certain action occurs (e.g., button click). The ViewModel defines the command and its associated logic. This separation of concerns makes the application more maintainable and testable.

Real-Life Use Case

Consider an application with a Save button. Using command binding, the button's click event would trigger the `SaveCommand` in the ViewModel. The ViewModel would then handle the logic of saving the data to a file or database. This allows for the reuse of the save logic across multiple UI elements (e.g., a menu item and a button both triggering the same save operation).

Best Practices

  • Use a RelayCommand or similar helper class to simplify the implementation of `ICommand`.
  • Ensure that your ViewModel implements `INotifyPropertyChanged` to notify the UI when properties change.
  • Keep the `CanExecute` method simple and efficient, as it will be called frequently to determine whether the command can be executed.
  • Consider using a command manager to handle command execution across multiple controls.

Interview Tip

Be prepared to explain the benefits of command binding, such as decoupling and testability. Also, be familiar with the `ICommand` interface and how to implement it.

When to Use Command Binding

Use command binding when you want to decouple the UI from the business logic and create a more maintainable and testable application. It's particularly useful when you have complex UI interactions that need to trigger actions in the ViewModel.

Memory Footprint

Command binding itself doesn't introduce a significant memory overhead. The memory footprint is primarily determined by the size of the ViewModel and the objects it references. However, be mindful of creating unnecessary `ICommand` instances or retaining references to large objects within the command's execution logic.

Alternatives

Alternatives to command binding include event handlers and code-behind logic. However, these approaches can lead to tightly coupled code that is more difficult to maintain and test. Messenger patterns can also be used, but are typically used for broader communications between ViewModels and are not direct replacements for command binding for direct UI interaction.

Pros

  • Decoupling of UI and business logic.
  • Improved testability.
  • Reusability of command logic.
  • Simplified UI code.

Cons

  • Requires understanding of the `ICommand` interface and related concepts.
  • Can add complexity to simple UI interactions.
  • May require a helper class like `RelayCommand` for easier implementation.

FAQ

  • What is the purpose of the `CanExecute` method?

    The `CanExecute` method determines whether the command can be executed at a given time. It allows you to disable or enable UI elements based on the state of the application.
  • Why use a `RelayCommand`?

    The `RelayCommand` is a convenient helper class that simplifies the implementation of the `ICommand` interface. It eliminates the need to create a separate class for each command.
  • How does `CommandManager.RequerySuggested` work?

    `CommandManager.RequerySuggested` is an event that is raised when the command system needs to re-evaluate the `CanExecute` state of commands. Subscribing to this event ensures that the UI is updated to reflect any changes in the command's availability.