Darp.CommunityToolkit.MvvmValidator 0.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Darp.CommunityToolkit.MvvmValidator --version 0.1.0
                    
NuGet\Install-Package Darp.CommunityToolkit.MvvmValidator -Version 0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Darp.CommunityToolkit.MvvmValidator" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Darp.CommunityToolkit.MvvmValidator" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Darp.CommunityToolkit.MvvmValidator" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Darp.CommunityToolkit.MvvmValidator --version 0.1.0
                    
#r "nuget: Darp.CommunityToolkit.MvvmValidator, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Darp.CommunityToolkit.MvvmValidator@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Darp.CommunityToolkit.MvvmValidator&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Darp.CommunityToolkit.MvvmValidator&version=0.1.0
                    
Install as a Cake Tool

Darp.CommunityToolkit.MvvmValidator

NuGet Downloads License .NET

An AOT- and trimming-compatible replacement for ObservableValidator from CommunityToolkit.Mvvm. It builds on the released toolkit; no fork needed.

ValidatingObservableObject derives from ObservableObject and implements INotifyDataErrorInfo. A source generator writes the validation for each derived type, so no reflection runs at runtime.

using System.ComponentModel.DataAnnotations;
using CommunityToolkit.Mvvm.ComponentModel;
using Darp.MvvmValidator;

public partial class SignUpViewModel : ValidatingObservableObject
{
    public SignUpViewModel() => ValidateAllProperties();

    [ObservableProperty]
    [Required]
    [StringLength(20, MinimumLength = 3)]
    [Display(Name = "User name")]
    public partial string? UserName { get; set; }

    [ObservableProperty]
    [Required]
    public partial string? Password { get; set; }

    [ObservableProperty]
    [Compare(nameof(Password))]
    public partial string? ConfirmPassword { get; set; }

    [CustomValidation(typeof(SignUpViewModel), nameof(ValidateInvite))]
    public string? InviteCode
    {
        get;
        set => SetProperty(ref field, value);
    }

    public static ValidationResult? ValidateInvite(string? code, ValidationContext context) =>
        code is null or "WELCOME" ? ValidationResult.Success : new ValidationResult("Unknown invite code");
}

Behavior

  • Every property with validation attributes is validated whenever it raises PropertyChanged, before subscribers are notified. This covers [ObservableProperty] fields and partial properties as well as hand-written SetProperty setters. [NotifyDataErrorInfo] and SetProperty(..., validate: true) are not needed.
  • Validation runs like Validator.TryValidateProperty: [Required] runs first and stops validation if it fails, then all other attributes run.
  • ValidateAllProperties() validates the current values, for example from the constructor.
  • SetErrors(propertyName, errors) publishes results from asynchronous or server-side validation. The next validation of that property replaces them. ErrorsChanged is only raised when the messages change.
  • ClearErrors() removes all errors, ClearErrors(propertyName) those of one property. Both forget that the properties were validated, so a reset form stays free of errors until its properties change again.
  • [CustomValidation] calls the method directly, and [Compare] reads the other property directly. Both work without reflection.
  • Messages and display names can come from resources (ErrorMessageResourceType/ErrorMessageResourceName, [Display(ResourceType = ...)]). The resource properties are read with reflection that the trimmer can prove through [DynamicallyAccessedMembers], so they also work with Native AOT.
  • When the target of a [Compare] changes, the comparing property is validated again, but only if it was validated before. An untouched "repeat password" field stays free of errors while the user types the password.

Requirements

  • .NET 10. Older frameworks don't have a trim-safe ValidationContext constructor.
  • Types that declare validated properties, and their containing types, must be partial and must not be file-local.
  • Attributes that can only target properties, like [Compare], need the property: target on [ObservableProperty] fields: [property: Compare(nameof(Password))].
  • Generated members start with __dmv_. Don't declare members with that prefix in view models.

Diagnostics

The package turns off the toolkit's MVVMTK0006, which only accepts ObservableValidator, and reports these instead:

Id Meaning
DMV0001 A validated type or one of its containing types is not partial, or is file-local. A code fix adds the missing partial modifiers
DMV0002 [CustomValidation] doesn't reference a single public static method with a matching signature that takes its arguments by value or in
DMV0003 An [ObservableProperty] member has validation attributes, but its type inherits neither ValidatingObservableObject nor ObservableValidator
DMV0004 [Compare] references a member that isn't a readable, accessible property
DMV0005 Validation of a property can't be generated: an attribute argument isn't a constant, an attribute uses a type that isn't accessible from the view model, or the property is a ref struct, a pointer or dynamic

The trim analyzer reports IL2026 where [Compare], [MinLength], [MaxLength] or [Length] is applied. The package suppresses these warnings when the generated code never reaches the reflection they warn about.

Preview packages

Every pull request publishes a preview package to the GitHub Packages feed https://nuget.pkg.github.com/rosslight/index.json. The pull request comment names the version. The feed requires a GitHub token with read:packages access.

Development

  • Format with CSharpier: dotnet tool restore and dotnet csharpier format .
  • tests/Darp.CommunityToolkit.MvvmValidator.Tests runs the runtime behavior. CI also publishes it with Native AOT and /warnaserror, which proves the generated validation is trim safe: dotnet publish tests/Darp.CommunityToolkit.MvvmValidator.Tests -c Release -r win-x64 /warnaserror
  • tests/Darp.CommunityToolkit.MvvmValidator.Generator.Tests covers the analyzer and snapshots the generated code with Verify. Review changed snapshots before accepting them.
  • Releases are cut by release-please from Conventional Commits on main.
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Darp.CommunityToolkit.MvvmValidator:

Package Downloads
Darp.Utils.Dialog

A very simple dialog service targeting avalonia

Darp.Utils.Dialog.FluentAvalonia

Implementation of Darp.Utils.Dialog compatible with Avalonia

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.1 53 11/9/2026
0.1.0 55 11/9/2026