100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
.NET

MVVM in WPF

How WPF's data binding engine, INotifyPropertyChanged, ICommand, and value converters combine to deliver the canonical MVVM implementation the pattern was originally designed for.

ArchitectureBeginner10 min readJul 10, 2026
Analogies

MVVM in WPF

WPF is the framework MVVM was originally designed for, and its binding engine is what makes the pattern practical: a XAML control's property, such as TextBox.Text, is bound with '{Binding OrderNumber}' to a ViewModel's public property, and WPF's binding infrastructure automatically pushes UI edits into the ViewModel and reflects ViewModel changes back into the UI, provided the ViewModel implements INotifyPropertyChanged and raises PropertyChanged when OrderNumber changes. This two-way data flow through the DataContext eliminates the code-behind event handlers ('button1_Click') that plagued WinForms-era development, replacing them with declarative bindings and ICommand implementations (RelayCommand/DelegateCommand) bound to Button.Command, keeping all interaction logic testable in the ViewModel rather than scattered across UI event handlers.

🏏

Cricket analogy: It's like a stadium's digital scoreboard automatically updating the moment the scorer's tablet records a run, and conversely, if an umpire corrects a scoring error on the scoreboard console, it flows back to the official scorebook — both sides stay in sync without a runner physically carrying updates back and forth.

INotifyPropertyChanged and Commanding

Implementing INotifyPropertyChanged by hand for every property is verbose, so most WPF MVVM code uses a base class or source generator: CommunityToolkit.Mvvm's [ObservableProperty] attribute generates the backing field, the public property, and the PropertyChanged raise automatically from a single private field declaration. For actions, WPF's ICommand interface (with CanExecute and Execute) is implemented via RelayCommand/DelegateCommand and bound with 'Command="{Binding SaveCommand}"'; WPF automatically disables the bound Button when CanExecute returns false and re-evaluates it via CommandManager.RequerySuggested or an explicit NotifyCanExecuteChanged call, so a Save button greys itself out the instant required fields become invalid without any manual UI-enabling code.

🏏

Cricket analogy: It's like an automatic honours board that updates itself the moment a batsman crosses fifty runs, rather than a scorer manually walking over to update the display — the notification is generated by the milestone itself, and similarly a bowling captain's option to review is automatically greyed out once the team has used all its DRS reviews.

csharp
public partial class OrderViewModel : ObservableObject
{
    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(SaveCommand))]
    private string orderNumber = string.Empty;

    [RelayCommand(CanExecute = nameof(CanSave))]
    private async Task SaveAsync()
    {
        await _orderService.SaveAsync(OrderNumber);
    }

    private bool CanSave() => !string.IsNullOrWhiteSpace(OrderNumber);
}
xml
<StackPanel>
    <TextBox Text="{Binding OrderNumber, UpdateSourceTrigger=PropertyChanged}" />
    <Button Content="Save" Command="{Binding SaveCommand}" />
</StackPanel>

ValueConverters and Design-Time Data

WPF bindings sometimes need to transform a value between ViewModel and View without polluting the ViewModel with UI-specific logic — an IValueConverter such as BooleanToVisibilityConverter turns a bool IsLoading property into a Visibility enum for a ProgressBar, keeping 'Visibility' (a WPF-only concept) out of the platform-agnostic ViewModel entirely. WPF's designer also supports d:DataContext bound to a design-time-only ViewModel instance (via d:DesignInstance or a design-time constructor branch checking DesignerProperties.GetIsInDesignMode), so Visual Studio's XAML designer can render realistic sample data in the Blend/VS designer surface without ever running the app's actual startup and DI-container wiring.

🏏

Cricket analogy: It's like a Duckworth-Lewis-Stern calculator converting raw overs-and-wickets data into a single adjusted target score for a rain-affected match — the conversion logic is a separate, specialized layer, not baked into the raw scorecard data itself.

Design-time data lets designers and developers iterate on XAML layout visually in Visual Studio/Blend without running the full application, but it must never leak into the runtime binding path — guard it behind DesignerProperties.GetIsInDesignMode(this) or a d:DataContext that only applies inside the XAML designer.

  • WPF's binding engine, via DataContext and INotifyPropertyChanged, is the original and canonical implementation MVVM was designed around.
  • Two-way bindings push UI edits into ViewModel properties and reflect ViewModel changes back into the UI automatically.
  • CommunityToolkit.Mvvm's [ObservableProperty] and [RelayCommand] source generators eliminate boilerplate for properties and commands.
  • ICommand's CanExecute lets bound controls like Button automatically enable/disable based on ViewModel state.
  • IValueConverter transforms values between ViewModel and View (e.g., bool to Visibility) without adding UI concepts to the ViewModel.
  • Design-time DataContext support lets XAML be visually authored with sample data without running the app.

Practice what you learned

Was this page helpful?

Topics covered

#NET#MVVMDesignPatternStudyNotes#MicrosoftTechnologies#MVVMInWPF#MVVM#WPF#INotifyPropertyChanged#Commanding#StudyNotes#SkillVeris