Implements MVVM pattern using CommunityToolkit.Mvvm with ObservableProperty attributes. Use when building ViewModels with source generators or implementing commands in WPF/AvaloniaUI.
View on GitHubchristian289/dotnet-with-claudecode
wpf-dev-pack
wpf-dev-pack/skills/implementing-communitytoolkit-mvvm/SKILL.md
January 23, 2026
Select agents to install to:
npx add-skill https://github.com/christian289/dotnet-with-claudecode/blob/main/wpf-dev-pack/skills/implementing-communitytoolkit-mvvm/SKILL.md -a claude-code --skill implementing-communitytoolkit-mvvmInstallation paths:
.claude/skills/implementing-communitytoolkit-mvvm/# CommunityToolkit.Mvvm Code Guidelines
A guide for implementing MVVM pattern using CommunityToolkit.Mvvm in WPF/AvaloniaUI.
## Project Structure
The templates folder contains a .NET 9 WPF project example.
```
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
```csharp
// ✅ Good: Single attribute written inline
[ObservableProperty] private string _userName = string.Empty;
[ObservableProperty] private int _age;
[ObservableProperty] private bool _isActive;
```
### Multiple Attributes - ObservableProperty Always Inline
```csharp
// ✅ 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
```csharp
// ❌ Bad: ObservableProperty on separate line
[NotifyPropertyChangedRecipients]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
[ObservableProperty]
private string _email = string.Empty;
```
## Complete ViewModel Example
```csharp
namespace MyApp.ViewModels;
using CommunityToolkit.Mvvm.Compo