Monumend.Net 2.0.3

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

Monumend.Net

A powerful .NET Standard 2.0 library providing configurable INotifyPropertyChanged implementation with extended event arguments that track both old and new values.

Features

? Configurable Behavior - Switch between API and Client modes
?? Extended Event Args - Track old and new property values
?? Thread-Safe - Safe event handler capture using Interlocked
?? Type-Safe - Generic implementation with compile-time type checking
? Performance Optimized - Conditional equality checking and event raising
?? Framework Agnostic - Works with WPF, Xamarin, MAUI, Avalonia, Blazor

Installation

dotnet add package Monumend.Net

Or via Package Manager Console:

Install-Package Monumend.Net

Quick Start

1. Configure on Startup

// In your application startup (e.g., App.xaml.cs for WPF)
using Monumend.Net.Models;

// For client applications (UI)
NotifyPropertyChangedExtensions.Configure(
    NotifyPropertyChangedExtensions.ClientConfiguration);

// For API/server applications
NotifyPropertyChangedExtensions.Configure(
    NotifyPropertyChangedExtensions.ApiConfiguration);

2. Create ViewModels

using Monumend.Net.Models;

public class PersonViewModel : VMO
{
    private string? _name;
    private int _age;

    public string? Name
    {
        get => _name;
        set => Set(value, ref _name);  // Clean and intuitive!
    }

    public int Age
    {
        get => _age;
        set
        {
            bool? changed = Set(value, ref _age);
            if (changed == true)
            {
                // Age changed - notify dependent property with automatic property name capture
                OnPropertyChanged(Age < 18, value >= 18);  // propertyName is automatically captured
            }
        }
    }

    public bool IsAdult => Age >= 18;
}

Tip: If your application targets .NET 8+, you can use the C# 13 field keyword for even cleaner code. See the "Using C# 13 Field Keyword" section below.

3. Subscribe to Changes

var person = new PersonViewModel();

// Standard PropertyChanged handler
person.PropertyChanged += (sender, e) =>
{
    Console.WriteLine($"Property {e.PropertyName} changed");
};

// Extended handler with old/new values
person.PropertyChanged += (sender, e) =>
{
    if (e is PropertyChangedExtendedEventArgs<string> args)
    {
        Console.WriteLine($"Name changed from '{args.OldValue}' to '{args.NewValue}'");
    }
};

person.Name = "John"; // Triggers both handlers

Advanced Usage

Custom Configuration

var customConfig = new NotifyPropertyChangedExtensions.Configuration
{
    RaiseEvents = true,
    CheckForValueChange = true
};

NotifyPropertyChangedExtensions.Configure(customConfig);

Value Change Detection

// Traditional backing field approach
private int _score;
public int Score
{
    get => _score;
    set
    {
        bool? changed = Set(value, ref _score);
        if (changed == true)
        {
            // Score actually changed - recalculate dependent properties
            RecalculateRanking();
            OnPropertyChanged(oldRank, newRank);  // propertyName automatically captured
        }
    }
}

// Modern C# 13 field keyword approach
public int Score
{
    get;
    set
    {
        bool? changed = Set(value, ref field);
        if (changed == true)
        {
            // Score actually changed
            RecalculateRanking();
        }
    }
}

Triggering Dependent Property Changes

public class PersonViewModel : VMO
{
    private string? _firstName;
    private string? _lastName;

    public string? FirstName
    {
        get => _firstName;
        set
        {
            if (Set(value, ref _firstName) == true)
            {
                // When FirstName changes, notify that FullName also changed
                NotifyPropertyChanged(nameof(FullName));
            }
        }
    }

    public string? LastName
    {
        get => _lastName;
        set
        {
            if (Set(value, ref _lastName) == true)
            {
                NotifyPropertyChanged(nameof(FullName));
            }
        }
    }

    public string FullName => $"{FirstName} {LastName}";
}

// Or using C# 13 field keyword
public class ModernPersonViewModel : VMO
{
    public string? FirstName
    {
        get;
        set
        {
            if (Set(value, ref field) == true)
            {
                NotifyPropertyChanged(nameof(FullName));
            }
        }
    }

    public string? LastName
    {
        get;
        set
        {
            if (Set(value, ref field) == true)
            {
                NotifyPropertyChanged(nameof(FullName));
            }
        }
    }

    // Important: Use property names, not backing fields
    public string FullName => $"{FirstName} {LastName}";
}

Manual Property Notification

public class PersonViewModel : VMO
{
    private string? _firstName;
    private string? _lastName;
    
    public string? FirstName
    {
        get => _firstName;
        set
        {
            if (Set(value, ref _firstName) == true)
            {
                // Option 1: Simple notification (v2.0.2+)
                OnPropertyChanged(nameof(FullName));
                
                // Option 2: With old/new values (v2.0.1+)
                // OnPropertyChanged(oldFullName, newFullName, nameof(FullName));
            }
        }
    }
    
    public string? LastName
    {
        get => _lastName;
        set
        {
            if (Set(value, ref _lastName) == true)
            {
                // Simple notification when you don't need value tracking
                OnPropertyChanged(nameof(FullName));
            }
        }
    }
    
    public string FullName => $"{FirstName} {LastName}".Trim();
    
    // Batch refresh multiple computed properties
    public void RefreshCalculatedProperties()
    {
        OnPropertyChanged(nameof(FullName));
        OnPropertyChanged(nameof(DisplayName));
        OnPropertyChanged(nameof(Summary));
    }
}

When to use each OnPropertyChanged overload:

Version History

  • v2.0.2 - Added protected OnPropertyChanged(string) overload for simple notifications
  • v2.0.1 - Improved OnPropertyChanged API with CallerMemberName support
  • v2.0.0 - Refactored API with improved parameter order Set(value, ref backingField)
  • v1.1.0 - Cleaned up API, removed redundant methods
  • v1.0.1 - Added package icon
  • v1.0.0 - Initial release
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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 was computed.  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 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.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.3 465 11/19/2025
2.0.2 332 11/17/2025
2.0.1 256 11/16/2025
2.0.0 308 11/13/2025
1.1.0 307 11/13/2025
1.0.1 310 11/13/2025
1.0.0 303 11/13/2025

v2.0.3 - Added comprehensive test suite with 49 tests providing 100% API coverage. Includes configuration tests, extended event args tests, client/API mode tests, VMO base class tests, thread safety tests, and integration tests. Enabled automated testing in CI/CD pipeline with code coverage reporting. All tests passing, execution under 2 seconds.