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.
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);
}<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
1. What must a WPF ViewModel implement for two-way data binding to automatically reflect property changes in the UI?
2. What does CommunityToolkit.Mvvm's [ObservableProperty] attribute generate?
3. How does WPF automatically disable a Button bound to a command whose required fields are invalid?
4. Why would a ViewModel use an IValueConverter like BooleanToVisibilityConverter rather than exposing a Visibility property directly?
5. What is the purpose of design-time DataContext support in WPF?
Was this page helpful?
You May Also Like
Dependency Injection in MVVM
How MVVM ViewModels receive their collaborators — data services, navigation, dialogs — via constructor injection instead of creating them directly, and why that makes apps testable and swappable.
Messaging and EventAggregator
How MVVM ViewModels communicate through a decoupled publish/subscribe message bus instead of direct references, and how to avoid the memory leaks that naive implementations cause.
MVVM in Blazor
How to apply MVVM in Blazor components despite the absence of a WPF-style binding engine, bridging ViewModel notifications into Blazor's render pipeline and handling Server vs WebAssembly differences.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics