Atc.UndoRedo 1.1.5

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

Atc.UndoRedo

A production-grade, platform-agnostic undo/redo framework for .NET.

NuGet Version NuGet Downloads Build Status License: MIT .NET 10

๐Ÿ“– Table of contents

โœจ Features

Core undo/redo:

  • Dual-stack undo/redo with configurable history limit
  • Thread-safe via ReaderWriterLockSlim
  • Pure .NET with zero platform dependencies

Command composition:

  • Command grouping for atomic multi-command transactions
  • Command merging to coalesce rapid changes (slider drags, typing)
  • Property tracking via delegate-based PropertyChangeCommand<T>
  • Rich commands carrying metadata, timestamps, and contexts

Advanced history control:

  • Named snapshots for save points in history
  • History serialization to persist and restore undo/redo state
  • Audit logging with timestamps for all operations
  • Non-linear history with branching redo paths
  • Operation approval to veto undo/redo operations
  • Memory-aware trimming with a configurable memory budget

๐Ÿ“ฆ Installation

Install the NuGet package:

dotnet add package Atc.UndoRedo

Or add it manually to your .csproj:

<PackageReference Include="Atc.UndoRedo" Version="1.0.0" />

Target framework: net10.0.

๐Ÿš€ Quick start

using Atc.UndoRedo.Commands;
using Atc.UndoRedo.Services;

var list = new List<string>();
var service = new UndoRedoService();

service.Execute(new UndoCommand(
    description: "Add item",
    execute: () => list.Add("Hello"),
    unExecute: () => list.Remove("Hello")));

service.Undo(); // list is empty
service.Redo(); // list contains "Hello"

๐Ÿงฉ Core concepts

IUndoCommand / UndoCommand

The fundamental command contract (Description, Execute(), UnExecute()). UndoCommand is a delegate-based implementation for the common case. See src/Atc.UndoRedo/Interfaces/IUndoCommand.cs and src/Atc.UndoRedo/Commands/UndoCommand.cs.

PropertyChangeCommand<T>

A pre-built command for reverting a single property change from oldValue to newValue. See src/Atc.UndoRedo/Commands/PropertyChangeCommand.cs.

UndoCommandGroup

Wraps a list of commands into a single atomic undo unit. Forward order on execute, reverse order on un-execute. See src/Atc.UndoRedo/Commands/UndoCommandGroup.cs.

IMergeableUndoCommand

Extends IUndoCommand with a MergeId and TryMergeWith(...) so consecutive compatible commands (typing, slider drags) collapse into one undo step. See src/Atc.UndoRedo/Interfaces/IMergeableUndoCommand.cs.

IRichUndoCommand / RichUndoCommand

Commands that carry extra metadata (id, timestamp, parameter, data, image, user-action flag, contexts). See src/Atc.UndoRedo/Commands/RichUndoCommand.cs.

UndoRedoService

The orchestrator. Exposes Execute, Undo, Redo, Clear, BeginGroup, SuspendRecording, snapshots, serialization, approvers, events, and CanUndo/CanRedo state. See src/Atc.UndoRedo/Services/UndoRedoService.cs.

๐Ÿ› ๏ธ Usage examples

Command grouping

BeginGroup returns an IDisposable scope. Any command executed inside the scope is collapsed into a single undo step when the scope disposes.

using (service.BeginGroup("Rename and move"))
{
    service.Execute(renameCommand);
    service.Execute(moveCommand);
}

service.Undo(); // reverts both in one step

Property tracking

var person = new Person { Name = "Ada" };
var oldName = person.Name;
var newName = "Grace";

service.Execute(new PropertyChangeCommand<string>(
    description: "Rename person",
    setter: v => person.Name = v,
    oldValue: oldName,
    newValue: newName));

Command merging

Implement IMergeableUndoCommand; successive commands with the same MergeId can fold into one.

public sealed class SliderChangeCommand : IMergeableUndoCommand
{
    public string Description => "Slider change";
    public int MergeId => 42;
    public bool IsObsolete => false;

    public void Execute() { /* apply newValue */ }
    public void UnExecute() { /* restore oldValue */ }

    public bool TryMergeWith(IUndoCommand other)
        => other is SliderChangeCommand next && /* update newValue from next */ true;
}

Named snapshots

var snapshot = service.CreateSnapshot("Before refactor");
// ... user performs several actions ...
service.RestoreSnapshot(snapshot); // jumps history back to the snapshot

History serialization

Commands that should survive a save must implement ISerializableUndoCommand. Provide an IUndoCommandDeserializer on load.

using var fs = File.Create("history.bin");
service.SaveHistory(fs);

using var fsIn = File.OpenRead("history.bin");
service.LoadHistory(fsIn, myDeserializer);

Audit logging

var logger = new UndoRedoAuditLogger();
var service = new UndoRedoService { AuditLogger = logger };

service.Execute(command);
foreach (var entry in logger.Entries)
{
    Console.WriteLine($"{entry.Timestamp:O} {entry.ActionType} {entry.Description}");
}

Operation approval

public sealed class ConfirmDestructive : IUndoOperationApprover
{
    public bool ApproveUndo(IUndoCommand command) => Prompt(command);
    public bool ApproveRedo(IUndoCommand command) => Prompt(command);

    private static bool Prompt(IUndoCommand c) => /* show dialog */ true;
}

service.RegisterApprover(new ConfirmDestructive());

Memory budget

MaxHistorySize caps command count; MaxHistoryMemory (bytes) caps estimated memory. Commands that implement IMemoryAwareUndoCommand contribute their EstimatedMemoryBytes to the budget.

var service = new UndoRedoService
{
    MaxHistorySize = 500,
    MaxHistoryMemory = 64 * 1024 * 1024, // 64 MiB
};

๐Ÿงช Samples

Three sample projects live under sample/:

  • Atc.UndoRedo.Sample.BlazorServer โ€” Blazor Server host. Run with dotnet run --project sample/Atc.UndoRedo.Sample.BlazorServer and open https://localhost:18774.
  • Atc.UndoRedo.Sample.BlazorWasm โ€” Blazor WebAssembly host. Run with dotnet run --project sample/Atc.UndoRedo.Sample.BlazorWasm and open https://localhost:18775.
  • Atc.UndoRedo.Sample.SharedDemo โ€” Razor class library shared by both hosts; contains the demo pages.

The demo pages cover:

  • BasicUndoRedo โ€” core Execute/Undo/Redo over a list.
  • CommandGrouping โ€” multi-command atomic transactions.
  • MergeableCommands โ€” coalescing rapid changes into one undo step.
  • PropertyTracking โ€” property-level change recording.
  • HistoryViewer โ€” inspecting the undo and redo stacks live.

โœ… Testing

Tests use xUnit v3 and live under test/Atc.UndoRedo.Tests. Run the full suite from the repository root:

dotnet test

๐Ÿ—‚๏ธ Project structure

atc-undoredo/
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ Atc.UndoRedo/              # The library
โ”œโ”€โ”€ sample/
โ”‚   โ”œโ”€โ”€ Atc.UndoRedo.Sample.BlazorServer/
โ”‚   โ”œโ”€โ”€ Atc.UndoRedo.Sample.BlazorWasm/
โ”‚   โ””โ”€โ”€ Atc.UndoRedo.Sample.SharedDemo/
โ”œโ”€โ”€ test/
โ”‚   โ””โ”€โ”€ Atc.UndoRedo.Tests/        # xUnit v3 test suite
โ”œโ”€โ”€ Atc.UndoRedo.slnx
โ”œโ”€โ”€ Directory.Build.props          # Shared build config, analyzers, versioning
โ”œโ”€โ”€ CHANGELOG.md
โ””โ”€โ”€ README.md

๐Ÿ“ Changelog

See CHANGELOG.md. The project follows Keep a Changelog and Semantic Versioning, with releases driven by release-please.

๐Ÿค Contributing

Issues and pull requests are welcome. Please open a GitHub issue to discuss larger changes before submitting a PR.

๐Ÿ“„ License

Licensed under the MIT License.

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.
  • net10.0

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Atc.UndoRedo:

Package Downloads
Atc.Wpf.Controls

WPF control library providing atomic UI controls including input controls, pickers, layouts, and progress indicators.

Atc.Wpf.UndoRedo

WPF undo/redo UI components (history view, keyboard behavior) on top of the Atc.UndoRedo service.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.5 115 4/18/2026
1.1.2 88 4/17/2026