implementing-communitytoolkit-mvvm
CommunityToolkit.Mvvm Code Guidelines
A guide for implementing MVVM pattern using CommunityToolkit.Mvvm in WPF.
Project Structure
The templates folder contains a WPF project example (use latest .NET per version mapping).
templates/
├── WpfMvvmSample.App/ ← WPF Application Project
│ ├── Views/
│ │ ├── MainWindow.xaml
│ │ └── MainWindow.xaml.cs
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── GlobalUsings.cs
│ └── WpfMvvmSample.App.csproj
└── WpfMvvmSample.ViewModels/ ← ViewModel Class Library (UI framework independent)
├── UserViewModel.cs
├── GlobalUsings.cs
└── WpfMvvmSample.ViewModels.csproj
Basic Principle
Use CommunityToolkit.Mvvm as the default for MVVM structure
ObservableProperty Attribute Writing Rules
Single Attribute - Write Inline
// ✅ Good: Single attribute written inline
[ObservableProperty] private string _userName = string.Empty;
[ObservableProperty] private int _age;
[ObservableProperty] private bool _isActive;
Multiple Attributes - ObservableProperty Always Inline
// ✅ Good: Multiple attributes, ObservableProperty always inline
[NotifyPropertyChangedRecipients]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
[ObservableProperty] private string _email = string.Empty;
[NotifyDataErrorInfo]
[Required(ErrorMessage = "Name is required.")]
[MinLength(2, ErrorMessage = "Name must be at least 2 characters.")]
[ObservableProperty] private string _name = string.Empty;
[NotifyPropertyChangedRecipients]
[NotifyCanExecuteChangedFor(nameof(DeleteCommand))]
[NotifyCanExecuteChangedFor(nameof(UpdateCommand))]
[ObservableProperty] private User? _selectedUser;
Bad Example
// ❌ Bad: ObservableProperty on separate line
[NotifyPropertyChangedRecipients]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
[ObservableProperty]
private string _email = string.Empty;
Complete ViewModel Example
namespace MyApp.ViewModels;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public sealed partial class UserViewModel : ObservableObject
{
// Single attribute
[ObservableProperty] private string _firstName = string.Empty;
[ObservableProperty] private string _lastName = string.Empty;
[ObservableProperty] private int _age;
// Multiple attributes - ObservableProperty inline
[NotifyPropertyChangedRecipients]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
[ObservableProperty] private string _email = string.Empty;
[NotifyCanExecuteChangedFor(nameof(DeleteCommand))]
[NotifyCanExecuteChangedFor(nameof(UpdateCommand))]
[ObservableProperty] private User? _selectedUser;
[RelayCommand(CanExecute = nameof(CanSave))]
private async Task SaveAsync()
{
// Save logic
}
private bool CanSave() => !string.IsNullOrWhiteSpace(Email);
}
Key Rules
- Single Attribute: Write
[ObservableProperty]inline right before the field declaration - Multiple Attributes: Write other attributes on separate lines, but
[ObservableProperty]is always inline at the end - Purpose: Improve code readability and maintain consistent coding style
More from christian289/dotnet-with-claudecode
converting-html-css-to-wpf-xaml
Converts HTML/CSS to WPF CustomControl XAML with correct patterns and common pitfall solutions. Use when transforming web designs to WPF, converting CSS animations to Storyboards, implementing CSS border-radius clipping, CSS pseudo-elements (::before/::after), or CSS transforms in XAML.
56publishing-wpf-apps
Guides WPF application publishing and installer options. Use when user mentions publish, deploy, release, packaging, or installer to help choose deployment method and installer technology.
14using-avalonia-collectionview
Provides CollectionView alternatives for AvaloniaUI using DataGridCollectionView and ReactiveUI. Use when filtering, sorting, or grouping collections in AvaloniaUI applications.
9designing-avalonia-customcontrol-architecture
Defines the basic solution structure for AvaloniaUI Desktop Applications using CustomControl. Use when creating new AvaloniaUI projects or designing stand-alone control styles with ControlTheme.
9using-xaml-property-element-syntax
Converts long inline XAML bindings to Property Element Syntax for better readability. Use when XAML binding expressions become too long or complex.
8managing-styles-resourcedictionary
Manages WPF Style definitions and ResourceDictionary patterns including BasedOn inheritance and resource merging. Use when building theme systems, organizing resources, or choosing between StaticResource and DynamicResource.
8