MVVM Part 2: The Command Spellbook
Up to now, the heroes simply appear in a scroll-like slideshow. Let’s add the ability to summon them one by one, like turning pages in a storybook. This introduces commands, one of the central spells of MVVM.
Act 8: The Power of Commands
Think of a Command as a “button spell.”
In the old world (non-MVVM apps), buttons call methods directly from the code-behind, creating messy entanglements.
In the MVVM world, buttons are bound to commands in the ViewModel — so the logic and interface remain cleanly separated.
Act 9: Preparing the Command Spell
Create a folder named Commands, and add a class called RelayCommand.cs.
using System;
using System.Windows.Input;
namespace RPGMVVMApp.Commands
{
public class RelayCommand : ICommand
{
private readonly Action<object> execute;
private readonly Func<object, bool> canExecute;
public event EventHandler CanExecuteChanged;
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.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);
}
}
}
This RelayCommand is our universal command pattern — like a reusable spell formula that any button can cast.
Act 10: Upgrading the Wizard (ViewModel)
Open HeroViewModel.cs and add logic for “Next Hero.”
using System.Collections.ObjectModel;
using RPGMVVMApp.Models;
using RPGMVVMApp.Commands;
using System.ComponentModel;
namespace RPGMVVMApp.ViewModels
{
public class HeroViewModel : INotifyPropertyChanged
{
private int currentHeroIndex;
private Hero currentHero;
public ObservableCollection<Hero> Heroes { get; set; }
public Hero CurrentHero
{
get => currentHero;
set
{
currentHero = value;
OnPropertyChanged(nameof(CurrentHero));
}
}
public RelayCommand NextHeroCommand { get; set; }
public HeroViewModel()
{
Heroes = new ObservableCollection<Hero>
{
new Hero { Name="Aeris the Brave", ImagePath="Images/hero1.png", Quote="Courage is the quiet voice that says 'try again'." },
new Hero { Name="Luna of the Vale", ImagePath="Images/hero2.png", Quote="The stars whisper to those who listen." },
new Hero { Name="Korran the Flame", ImagePath="Images/hero3.png", Quote="Fire tests all things." }
};
CurrentHero = Heroes[0];
currentHeroIndex = 0;
NextHeroCommand = new RelayCommand(o => NextHero());
}
private void NextHero()
{
currentHeroIndex = (currentHeroIndex + 1) % Heroes.Count;
CurrentHero = Heroes[currentHeroIndex];
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
}
You’ve now given the wizard (ViewModel) the ability to change heroes — one command, cleanly separated from the View.
Act 11: Enchanting the View
Edit MainWindow.xaml to show just one hero and add a button:
<Window x:Class="RPGMVVMApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Hero Showcase" Height="400" Width="600" Background="#1C1C1C">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Image Source="{Binding CurrentHero.ImagePath}" Height="200" Margin="0,10"/>
<TextBlock Text="{Binding CurrentHero.Name}" FontSize="24" Foreground="Gold" TextAlignment="Center"/>
<TextBlock Text="{Binding CurrentHero.Quote}" FontSize="16" Foreground="LightGray" TextAlignment="Center" Margin="0,5,0,10"/>
<Button Content="Next Hero"
Command="{Binding NextHeroCommand}"
Width="120"
Background="#444"
Foreground="White"
Padding="5"/>
</StackPanel>
</Grid>
</Window>
Now, every time learners click the Next Hero button, the ViewModel’s command runs and updates the displayed hero. No event handlers, no spaghetti — pure data binding magic.
Act 12: Reflection — The Design Pattern Revealed
What you’ve created isn’t just a slideshow. It’s a micro-architecture — a living example of separation of concerns.
| Role | In Our App | Analogy |
|---|---|---|
| Model | Hero class | The scroll of character stats |
| View | MainWindow.xaml | The enchanted mirror where players see the hero |
| ViewModel | HeroViewModel.cs | The wizard interpreting commands and fetching data |
This structure keeps apps clean and testable. It’s how large-scale software — from finance dashboards to video editors — stays organized.
Mini Challenge for Learners
Add a “Previous Hero” command or an “Add New Hero” feature.
Can they do it without touching the View’s code-behind? That’s the test of true MVVM mastery.
