MvvmEssence 2.0.0

dotnet add package MvvmEssence --version 2.0.0
                    
NuGet\Install-Package MvvmEssence -Version 2.0.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="MvvmEssence" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MvvmEssence" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="MvvmEssence" />
                    
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 MvvmEssence --version 2.0.0
                    
#r "nuget: MvvmEssence, 2.0.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 MvvmEssence@2.0.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=MvvmEssence&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=MvvmEssence&version=2.0.0
                    
Install as a Cake Tool

MvvmEssence

NuGet License: MIT

MvvmEssence is a lightweight, high-performance MVVM framework for .NET 8 - 10, designed to eliminate boilerplate code while providing powerful features for modern .NET applications, for maximum productivity with minimal overhead

🚀 Key Features

  • Simplified Property Management - No more backing fields or manual notifications
  • Command Caching - Efficient command creation
  • Async Command Support - Proper async/await handling with exception management
  • Command Template Support - Avoid repeated command handler code
  • Attribute-Based Validation - Declarative validation with comprehensive error reporting
  • Transaction / Undo Support - Built-in transaction-based change tracking
  • Change Tracking - Automatic dirty state monitoring
  • Enhanced Collections - Batch operations and property change notifications
  • Dependency Injection Helper - Automatic service registration

đŸ“Ļ Compatibility

  • .NET 8, 9 and 10
  • WPF, MAUI.NET - Cross-platform support

🏁 Quick Start

1. Install the Package

dotnet add package MvvmEssence

2. Create Your ViewModel

using Brain2CPU.MvvmEssence;

public class PersonViewModel : ViewModelBase
{
    [Required]
    [StringLength(2, 50)]
    public string Name
    {
        get => Get<string>();
        set => Set(value, SaveCommand);
    }

    [Email]
    public string Email
    {
        get => Get<string>();
        set => Set(value);
    }

    [Range(0, 120)]
    public int Age
    {
        get => Get<int>();
        set => Set(value);
    }

    public RelayCommand SaveCommand => Get(() => Save(), () => !IsBusy && IsObjectValid);
    
    private void Save()
    {
        // Save logic here
    }
}

3. Use in XAML

<TextBox Text="{Binding Name}" />
<Button Command="{Binding SaveCommand}" Content="Save" />

📖 Detailed Usage

Properties - Before vs After

Traditional MVVM:

private string _name;
public string Name
{
    get => _name;
    set
    {
        if (_name == value) 
            return;
        _name = value;
        NotifyPropertyChanged();
        SaveCommand?.RaiseCanExecuteChanged();
    }
}

MvvmEssence:

public string Name
{
    get => Get<string>();
    set => Set(value, SaveCommand);
}

Commands - Before vs After

Traditional MVVM:

private ICommand _saveCommand;
public ICommand SaveCommand => 
    _saveCommand ??= new RelayCommand(Save, () => !IsBusy && IsValid);

MvvmEssence:

public RelayCommand SaveCommand => Get(() => Save(), () => !IsBusy && IsValid);

Async Commands

public RelayCommandAsync LoadDataCommand => Get(LoadDataAsync, () => !IsBusy);

private async Task LoadDataAsync()
{
    // Async operation
    await SomeApiCall();
}

Exception Handling

public MyViewModel()
{
    // Global exception handler for templated commands
    ExceptionHandler = ex => 
    {
        Debug.WriteLine($"Command error: {ex.Message}");
        // Handle or log exception
    };

    public RelayCommand<string?> ChangeNameCommand =>
        GetTemplated<string?>(ChangeName, () => !IsBusy && !string.IsNullOrEmpty(Name));
}

✅ Validation System

Attribute-Based Validation

public class UserRegistrationViewModel : ViewModelBase
{
    [Required()]
    [StringLength(3, 20)]
    public string Username
    {
        get => Get<string>();
        set => Set(value);
    }

    [Required]
    [Email]
    public string Email
    {
        get => Get<string>();
        set => Set(value);
    }

    [Required]
    [StringLength(8, 100)]
    [Regex(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])")]
    public string Password
    {
        get => Get<string>();
        set => Set(value);
    }

    // Validation state properties
    public bool IsValid => IsObjectValid;
    public string ValidationSummary => string.Join(", ", 
        ValidationErrors.SelectMany(kvp => kvp.Value));
}

Available Validation Attributes

  • [Required] - Property cannot be null or empty
  • [Number<T>] - Value must be a number of the specified type
  • [Range<T>(min, max)] - Numeric range validation
  • [Between<T>(min, max)] - IComparable range validation
  • [StringLength(min, max)] - String length validation
  • [Email] - Email format validation
  • [Date] - DateOnly validation
  • [DateTime] - DateTime validation
  • [Regex(pattern)] - Regular expression validation
  • [Enum<T>] - Value must be from the specified enum
  • [CustomValidation<T>] - T must implement IValidator, used for complex scenarios

â†Šī¸ Transaction / Undo Support

public class DocumentViewModel : ObservableObject
{
    public string Title
    {
        get => Get<string>();
        set => Set(value);
    }

    public string Content
    {
        get => Get<string>();
        set => Set(value);
    }

    // Grouped operations
    public void UpdateDocument(string title, string content)
    {
        Transaction.Begin();
        Title = title;
        Content = content;
        Transaction.Commit();
    }

    public RelayCommand UndoCommand => Get(() => Transaction.Undo(), () => CanUndo);
}

📚 Enhanced Collections

ObservableCollectionEx provides advanced collection features:

public class ItemsViewModel : ViewModelBase
{
    public ObservableCollectionEx<ItemViewModel> Items { get; } = 
        new ObservableCollectionEx<ItemViewModel>();

    public void LoadItems(IEnumerable<ItemViewModel> items)
    {
        // Efficient bulk operations
        Items.SuppressNotification = true;
        Items.Clear();
        Items.AddRange(items);
        Items.SuppressNotification = false; // Single notification
    }

    public void RemoveSelected(IEnumerable<ItemViewModel> selected)
    {
        Items.RemoveRange(selected);
    }
}

Key Features:

  • Batch Operations - AddRange(), RemoveRange()
  • Notification Control - SuppressNotification property
  • Item Property Changes - Automatically propagates item property changes, restricted to INotifyPropertyChanged

đŸ—ī¸ Dependency Injection Integration

DiscoverComponents automates service registration:

// In MauiProgram.cs or Startup.cs
var discover = new DiscoverComponents(typeof(App).Assembly, type =>
{
    if (type.Namespace?.Contains("ViewModels") == true)
        return ClassRegistrationOption.AsTransient;
        
    if (type.Namespace?.Contains("Services") == true)
        return ClassRegistrationOption.AsSingleton;

    return ClassRegistrationOption.Skip;
});

discover.RegisterItems(
    singletonType => builder.Services.AddSingleton(singletonType),
    transientType => builder.Services.AddTransient(transientType),
    (implType, interfaceType) => builder.Services.AddSingleton(interfaceType, implType),
    (implType, interfaceType) => builder.Services.AddTransient(interfaceType, implType));

Attribute-Based Registration

[RegisterAsSingleton]
public class DataService : IDataService
{
    // Implementation
}

[RegisterAsTransient]
public class MainViewModel : ViewModelBase
{
    // ViewModel implementation
}

🔧 Advanced Features

Custom Equality Comparers

public DateTime DateTo
{
    get => Get<DateTime>();
    set => Set(value, RefreshCommand, (d1, d2) => d1.Date == d2.Date);
}

Async Initialization

public class DataViewModel : ViewModelBase
{
    protected override async Task InitializeAsync()
    {
        // Async initialization
        Data = await LoadDataAsync();
    }
}

Change Tracking

public class EditableViewModel : ViewModelBase
{
    public bool HasChanges => IsChanged;
    public IReadOnlyList<string> ChangedProperties => ChangedFields;
    
    public void ResetChanges()
    {
        base.ResetChanges();
    }
}

🔄 Migration Guide

From MvvmEssence 1.3.*

The validation method is changed, the lambda based validation defined in the Set overload is not working in the new version, you must switch to the attribute based validation. For more complex scenarios the easiest way is to move the existing validation code into the IsValid method of a new class implementing IValidator.

From CommunityToolkit.Mvvm

// Before (CommunityToolkit)
[ObservableProperty]
private string _name;

// After (MvvmEssence)
public string Name
{
    get => Get<string>();
    set => Set(value);
}

From Prism

// Before (Prism)
private string _name;
public string Name
{
    get => _name;
    set => SetProperty(ref _name, value);
}

// After (MvvmEssence)
public string Name
{
    get => Get<string>();
    set => Set(value);
}

📚 Sample Projects

Check out the included sample applications:

  • MAUI Sample - Complete cross-platform app demonstrating all features
  • Unit Tests - Comprehensive test suite showing usage patterns

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 442 12/10/2025
1.4.3 395 1/12/2024
1.4.2 319 12/18/2023
1.4.1 232 12/13/2023
1.4.0 198 12/6/2023
1.3.0 258 7/26/2023
1.2.1 538 10/17/2022
1.2.0 558 5/26/2022
1.1.0 497 9/7/2021
1.0.2 584 1/17/2021
1.0.1 596 10/28/2020
1.0.0 647 10/18/2020