ICommand
MVVM
WPF
C#
DataBinding

ICommand MVVM implementation

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In MVVM, ICommand lets the view trigger ViewModel logic without code-behind event handlers. The usual implementation is a reusable command class, often called RelayCommand, that wraps an execute action and an optional CanExecute rule.

Why ICommand Exists In MVVM

The point of MVVM is to keep UI behavior testable and separate from the view. Instead of writing a click handler in the window code-behind, you expose a command from the ViewModel and bind the button to it.

The ICommand interface has three parts:

  • 'Execute'
  • 'CanExecute'
  • 'CanExecuteChanged'

That is enough to model most button, menu, and toolbar actions in WPF.

A Simple RelayCommand Implementation

Here is a straightforward implementation:

csharp
1using System;
2using System.Windows.Input;
3
4public sealed class RelayCommand : ICommand
5{
6    private readonly Action _execute;
7    private readonly Func<bool>? _canExecute;
8
9    public RelayCommand(Action execute, Func<bool>? canExecute = null)
10    {
11        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
12        _canExecute = canExecute;
13    }
14
15    public bool CanExecute(object? parameter) => _canExecute?.Invoke() ?? true;
16
17    public void Execute(object? parameter) => _execute();
18
19    public event EventHandler? CanExecuteChanged
20    {
21        add => CommandManager.RequerySuggested += value;
22        remove => CommandManager.RequerySuggested -= value;
23    }
24}

This implementation works well for commands that do not need a parameter. CommandManager.RequerySuggested is convenient in WPF because it prompts the UI to reevaluate whether buttons should be enabled.

Use The Command In A ViewModel

Now expose a command from the ViewModel:

csharp
1using System.ComponentModel;
2using System.Runtime.CompilerServices;
3using System.Windows.Input;
4
5public class MainViewModel : INotifyPropertyChanged
6{
7    private string _name = string.Empty;
8
9    public string Name
10    {
11        get => _name;
12        set
13        {
14            if (_name == value) return;
15            _name = value;
16            OnPropertyChanged();
17            CommandManager.InvalidateRequerySuggested();
18        }
19    }
20
21    public ICommand SaveCommand { get; }
22
23    public MainViewModel()
24    {
25        SaveCommand = new RelayCommand(Save, CanSave);
26    }
27
28    private void Save()
29    {
30        Name = Name.Trim();
31    }
32
33    private bool CanSave()
34    {
35        return !string.IsNullOrWhiteSpace(Name);
36    }
37
38    public event PropertyChangedEventHandler? PropertyChanged;
39
40    private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
41    {
42        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
43    }
44}

Here the command stays disabled until Name contains non-whitespace text. That is the main value of CanExecute: the UI updates its enabled state automatically from ViewModel logic.

Bind It In XAML

The view binding stays simple:

xml
1<StackPanel Margin="16">
2    <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
3    <Button Content="Save" Command="{Binding SaveCommand}" Margin="0,8,0,0" />
4</StackPanel>

The button does not know anything about the save logic. It only knows it should invoke the bound command.

That keeps the view declarative and the behavior testable.

Support Command Parameters When Needed

Many MVVM projects also define a generic version so commands can receive a typed parameter.

csharp
1using System;
2using System.Windows.Input;
3
4public sealed class RelayCommand<T> : ICommand
5{
6    private readonly Action<T?> _execute;
7    private readonly Predicate<T?>? _canExecute;
8
9    public RelayCommand(Action<T?> execute, Predicate<T?>? canExecute = null)
10    {
11        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
12        _canExecute = canExecute;
13    }
14
15    public bool CanExecute(object? parameter) => _canExecute?.Invoke((T?)parameter) ?? true;
16
17    public void Execute(object? parameter) => _execute((T?)parameter);
18
19    public event EventHandler? CanExecuteChanged
20    {
21        add => CommandManager.RequerySuggested += value;
22        remove => CommandManager.RequerySuggested -= value;
23    }
24}

That is useful for list actions, selected-item commands, and context menu operations.

Common Pitfalls

The biggest mistake is putting UI logic back into code-behind and only using ICommand superficially. If the behavior matters to the view state, it usually belongs in the ViewModel.

Another common issue is forgetting to refresh CanExecute. If the underlying state changes and the UI does not requery the command, buttons can stay stuck enabled or disabled.

People also overcomplicate command classes. A small reusable RelayCommand is enough for many applications. You do not need a custom command type for every button.

Finally, be careful with async work. An async void command body can hide exceptions and reentrancy problems. For long-running tasks, use an async-aware command pattern rather than pretending every action is instant.

Summary

  • 'ICommand is the MVVM bridge between the view and ViewModel actions.'
  • A RelayCommand wraps execute logic and optional enablement rules.
  • 'CanExecute controls whether the bound UI element is enabled.'
  • XAML binds directly to commands, keeping the view free of event-handler logic.
  • For parameters or async workflows, extend the basic pattern deliberately instead of bypassing it.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.