Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
github avatar

Mvvm Toolkit

  • 1 installs
  • 37.5k repo stars
  • Updated August 5, 2026
  • github/awesome-copilot

mvvm-toolkit skill documents CommunityToolkit.

About

mvvm-toolkit skill documents CommunityToolkit.Mvvm (the MVVM Toolkit) core: source generators ([ObservableProperty], [RelayCommand], [NotifyPropertyChangedFor], [NotifyCanExecuteChangedFor], [NotifyDataErrorInfo]), base classes (ObservableObject / ObservableValidator / ObservableRecipient), commands (RelayCommand / AsyncRelayCo. name: mvvm-toolkit description: 'CommunityToolkit.Mvvm (the MVVM Toolkit) core: source generators ([ObservableProperty], [RelayCommand], [NotifyPropertyChangedFor], [NotifyCanExecuteChangedFor], [NotifyDataErrorInfo]), base classes (ObservableObject / ObservableValidator / ObservableRecipient), commands (RelayCommand / AsyncRelayCommand), and validation. Companion skills: mvvm-toolkit-messenger fo

  • CommunityToolkit.
  • Platform-specific setup patterns for mvvm-toolkit.
  • Evidence-backed steps from upstream SKILL.md.
  • When-to-use criteria for mvvm-toolkit versus alternatives.

Mvvm Toolkit by the numbers

  • 1 all-time installs (skills.sh)
  • Ranked #1,980 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
At a glance

mvvm-toolkit capabilities & compatibility

Capabilities
mvvm toolkit quick start · mvvm toolkit when to use guidance · mvvm toolkit integration patterns
From the docs

What mvvm-toolkit says it does

Use this skill when authoring or reviewing ViewModels, properties,
SKILL.md
commands, or validation in apps that use `CommunityToolkit.Mvvm` 8.x.
SKILL.md
npx skills add https://github.com/github/awesome-copilot --skill mvvm-toolkit

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs1
repo stars37.5k
Last updatedAugust 5, 2026
Repositorygithub/awesome-copilot

How do I use mvvm-toolkit correctly?

CommunityToolkit.Mvvm (the MVVM Toolkit) core: source generators ([ObservableProperty], [RelayCommand], [NotifyPropertyChangedFor], [NotifyCanExecuteChangedFor], [NotifyDataErrorInfo]), base classes (

Who is it for?

Teams implementing mvvm-toolkit workflows from the catalog.

Skip if: Skip when requirements clearly match a different specialized stack.

When should I use this skill?

User asks about mvvm-toolkit, communitytoolkit.mvvm (the mvvm toolkit) core: source generators ([observableproperty], [r.

What you get

Working mvvm-toolkit setup with validated configuration and next steps.

Files

SKILL.mdMarkdownGitHub ↗

CommunityToolkit.Mvvm (core)

Use this skill when authoring or reviewing ViewModels, properties, commands, or validation in apps that use CommunityToolkit.Mvvm 8.x.

Companion skills. Load `mvvm-toolkit-messenger` for IMessenger
pub/sub patterns. Load `mvvm-toolkit-di` for
Microsoft.Extensions.DependencyInjection integration.
Quick recap. [ObservableProperty] on private fields in partial
classes; [RelayCommand] on instance methods; inherit from
ObservableObject (or ObservableValidator for input forms,
ObservableRecipient when using IMessenger).

---

Package & setup

<ItemGroup>
  <PackageReference Include="CommunityToolkit.Mvvm" Version="8.*" />
</ItemGroup>

Targets: netstandard2.0, netstandard2.1, net6.0+. Works on .NET, .NET Framework, Mono. Source generators ship in the same NuGet — no extra analyzer reference required.

Namespaces:

using CommunityToolkit.Mvvm.ComponentModel;   // ObservableObject, [ObservableProperty]
using CommunityToolkit.Mvvm.Input;             // [RelayCommand], RelayCommand, AsyncRelayCommand
Universal rule. Every type that uses [ObservableProperty] or
[RelayCommand] — and every enclosing type, if nested — must be
declared partial. Without it, the generators emit
MVVMTK0008 / MVVMTK0042.

---

Source generators cheat sheet

AttributeApplied toGenerates
[ObservableProperty]private fieldPublic INotifyPropertyChanged property + OnXxxChanging/OnXxxChanged partial-method hooks
[NotifyPropertyChangedFor(nameof(Other))]observable fieldAlso raises PropertyChanged for the listed property
[NotifyCanExecuteChangedFor(nameof(MyCommand))]observable fieldCalls MyCommand.NotifyCanExecuteChanged() on change
[NotifyDataErrorInfo]observable field on ObservableValidatorCalls ValidateProperty(value) from the setter
[NotifyPropertyChangedRecipients]observable field on ObservableRecipientBroadcast(old, new) after the change
[RelayCommand]instance methodLazy RelayCommand / AsyncRelayCommand exposed as IRelayCommand / IAsyncRelayCommand
[RelayCommand(CanExecute = nameof(CanX))]instance methodWires CanExecute to a method or property
[RelayCommand(IncludeCancelCommand = true)]async method with CancellationTokenAlso generates XxxCancelCommand
[RelayCommand(AllowConcurrentExecutions = true)]async methodAllows queued/parallel invocations (default disables while running)
[RelayCommand(FlowExceptionsToTaskScheduler = true)]async methodSurfaces exceptions via ExecutionTask instead of awaiting and rethrowing
[property: SomeAttr]observable field or [RelayCommand] methodForwards SomeAttr onto the generated property (e.g., [JsonIgnore])

Naming. Field name / _name / m_nameName. Method LoadAsyncLoadCommand (the Async suffix is stripped; a leading On is also stripped).

See `references/source-generators.md` for the full attribute reference with generated-code samples.

---

ViewModel patterns

Simple observable property

public partial class ContactViewModel : ObservableObject
{
    [ObservableProperty]
    private string? name;
}

Hooks: OnXxxChanging / OnXxxChanged

[ObservableProperty]
private string? name;

partial void OnNameChanged(string? value) =>
    Logger.LogInformation("Name changed to {Name}", value);

Both single-arg (value) and two-arg (oldValue, newValue) overloads are available. Implement only the ones you need; unimplemented hooks are elided by the compiler (zero runtime cost).

Dependent properties + dependent commands

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private string? firstName;

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private string? lastName;

public string FullName => $"{FirstName} {LastName}".Trim();

Wrapping a non-observable model

public sealed class ObservableUser(User user) : ObservableObject
{
    public string Name
    {
        get => user.Name;
        set => SetProperty(user.Name, value, user, (u, n) => u.Name = n);
    }
}

Pass a static lambda (no captured state) to keep the call allocation-free.

---

Commands

[RelayCommand]
private void Refresh() => Items.Reset();

[RelayCommand]
private async Task LoadAsync()
{
    foreach (var item in await service.GetItemsAsync())
        Items.Add(item);
}

[RelayCommand(IncludeCancelCommand = true)]
private async Task DownloadAsync(CancellationToken token)
{
    await using var stream = await http.GetStreamAsync(url, token);
    // ...
}

[RelayCommand(CanExecute = nameof(CanSave))]
private Task SaveAsync() => repo.SaveAsync(Name!);

private bool CanSave() => !string.IsNullOrWhiteSpace(Name);

Reach for manual RelayCommand / AsyncRelayCommand constructors only when you must own the command's lifetime explicitly or compose it from non-trivial sources. The attribute style covers ~95% of cases.

See `references/relaycommand-cookbook.md` for sync / async / cancellable / concurrency / error-surfacing recipes.

---

Base class selection

Base classUse when
ObservableObjectDefault. INotifyPropertyChanged + INotifyPropertyChanging + SetProperty overloads + SetPropertyAndNotifyOnCompletion for Task properties
ObservableValidatorThe VM needs INotifyDataErrorInfo (forms, settings input)
ObservableRecipientThe VM sends or receives IMessenger messages — see the `mvvm-toolkit-messenger` skill

C# is single-inheritance: ObservableValidator and ObservableRecipient both extend ObservableObject, so combining them requires composition (e.g., inject IMessenger into an ObservableValidator).

---

Validation

using System.ComponentModel.DataAnnotations;

public sealed partial class RegistrationViewModel : ObservableValidator
{
    [ObservableProperty]
    [NotifyDataErrorInfo]
    [Required, MinLength(2), MaxLength(100)]
    private string? name;

    [ObservableProperty]
    [NotifyDataErrorInfo]
    [Required, EmailAddress]
    private string? email;

    [RelayCommand]
    private void Submit()
    {
        ValidateAllProperties();
        if (HasErrors) return;
        // submit...
    }
}

Other entry points: TrySetProperty, ValidateProperty(value, name), ClearAllErrors(), GetErrors(propertyName). Custom rules support [CustomValidation] methods and custom ValidationAttribute subclasses.

See `references/validation.md` for the full validator surface area.

---

Top pitfalls

1. Forgetting `partial`. Class (and every enclosing type) must be partial. Compile error MVVMTK0008 / MVVMTK0042. 2. PascalCase field name. [ObservableProperty] private string Name; collides with the generated property. Use name, _name, or m_name. 3. `async void` on `[RelayCommand]`. The generator only wraps Task-returning methods as IAsyncRelayCommand. async void becomes a sync RelayCommand and exceptions are unobserved. Always return Task. 4. Forgetting `[NotifyCanExecuteChangedFor]`. The Save button stays disabled even though CanSave() would now return true. 5. Mutating the same reference held by an `[ObservableProperty]` field. EqualityComparer<T>.Default returns true, no notification fires. Replace the instance instead of mutating it.

For the full diagnostic table (MVVMTK0xxx) and more pitfalls, see `references/troubleshooting.md`.

---

End-to-end mini walkthrough

A two-pane Notes app demonstrating generators + commands + [NotifyCanExecuteChangedFor]:

public sealed partial class NoteViewModel(INotesService notes,
    IMessenger messenger) : ObservableRecipient(messenger)
{
    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(SaveCommand))]
    [NotifyCanExecuteChangedFor(nameof(DeleteCommand))]
    private string? filename;

    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(SaveCommand))]
    private string? text;

    [RelayCommand(CanExecute = nameof(CanSave))]
    private Task SaveAsync()
    {
        Messenger.Send(new NoteSavedMessage(Filename!));
        return notes.SaveAsync(Filename!, Text!);
    }

    [RelayCommand(CanExecute = nameof(CanDelete))]
    private Task DeleteAsync() => notes.DeleteAsync(Filename!);

    private bool CanSave() =>
        !string.IsNullOrWhiteSpace(Filename) && !string.IsNullOrEmpty(Text);
    private bool CanDelete() => !string.IsNullOrWhiteSpace(Filename);
}

For the full sample (DI wiring, View code-behind, XAML, unit tests), see `references/end-to-end-walkthrough.md`.

---

References & companion skills

TopicWhere
Source generator attribute reference`references/source-generators.md`
RelayCommand recipes`references/relaycommand-cookbook.md`
Validation deep dive`references/validation.md`
Full Notes-app walkthrough`references/end-to-end-walkthrough.md`
MVVMTK0xxx diagnostics & pitfalls`references/troubleshooting.md`
Messenger pub/subCompanion skill: `mvvm-toolkit-messenger`
`Microsoft.Extensions.DependencyInjection` wiringCompanion skill: `mvvm-toolkit-di`

External sources:

  • Toolkit overview: <https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/>
  • WinUI MVVM Toolkit tutorial: <https://learn.microsoft.com/en-us/windows/apps/tutorials/winui-mvvm-toolkit/intro>
  • Source: <https://github.com/CommunityToolkit/dotnet>
  • Samples: <https://github.com/CommunityToolkit/MVVM-Samples>

Related skills

FAQ

What does mvvm-toolkit do?

mvvm-toolkit skill documents CommunityToolkit.

When should I use mvvm-toolkit?

User asks about mvvm-toolkit, communitytoolkit.mvvm (the mvvm toolkit) core: source generators ([observableproperty], [r.

Is this skill safe to install?

Review the Security Audits panel on this page before installing in production.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.