Shos.UndoRedoList 1.0.5

dotnet add package Shos.UndoRedoList --version 1.0.5
NuGet\Install-Package Shos.UndoRedoList -Version 1.0.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="Shos.UndoRedoList" Version="1.0.5" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Shos.UndoRedoList --version 1.0.5
#r "nuget: Shos.UndoRedoList, 1.0.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.
// Install Shos.UndoRedoList as a Cake Addin
#addin nuget:?package=Shos.UndoRedoList&version=1.0.5

// Install Shos.UndoRedoList as a Cake Tool
#tool nuget:?package=Shos.UndoRedoList&version=1.0.5

Shos.UndoRedoList

List and ObservableCollection which support undo/redo.

NuGet

You can install Shos.UndoRedoList to your project with NuGet on Visual Studio.

Package Manager

PM>Install-Package Shos.UndoRedoList -version 1.0.5

.NET CLI

>dotnet add package Shos.UndoRedoList --version 1.0.5

PackageReference

<PackageReference Include="Shos.UndoRedoList" Version="1.0.5" />

Projects

Types for collection which supports undo/redo.

Tests for Shos.UndoRedoList.

Performance tests for Shos.UndoRedoList.

Sample WPF app for UndoRedoObservableCollection.

Shos.UndoRedoList.SampleApp

Types

class UndoRedoList<TElement, TList> : IList<TElement> where TList : IList<TElement>, new()

IList implemented collection which supports undo/redo.

class UndoRedoList<TElement> : UndoRedoList<TElement, List<TElement>>

List implemented collection which supports undo/redo.

class UndoRedoObservableCollection<TElement> : UndoRedoList<TElement, ObservableCollection<TElement>>, INotifyCollectionChanged

ObservableCollection which supports undo/redo.

class RingBuffer<TElement> : IEnumerable<TElement>

Circular buffer - Wikipedia

In computer science, a circular buffer, circular queue, cyclic buffer or ring buffer is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. This structure lends itself easily to buffering data streams.

class UndoRedoRingBuffer<TElement> : RingBuffer<TElement>

Specialized RingBuffer for undo/redo.

struct ModuloArithmetic : IEquatable<ModuloArithmetic>

Modular arithmetic - Wikipedia

In mathematics, modular arithmetic is a system of arithmetic for integers, where numbers "wrap around" when reaching a certain value, called the modulus.

static class EnumerableExtensions

Extension methods for IEnumerable.

Class diagram

*.puml files in Shos.UndoRedoList/Documents/ClassDiagrams are class diagram for PlantUML.

The following image is a class diagram made from these *.puml files.

Shos.UndoRedoList class diagram

Larger class diagram image is here.

Samples

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shos.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;

namespace Shos.UndoRedoList.Tests
{
    [TestClass]
    public class SampleTest
    {
        [TestMethod]
        public void UndoRedoTest()
        {
            // list which support undo/redo.
            var target = new UndoRedoList<int, List<int>>();

            Assert.IsFalse(target.CanUndo);
            Assert.IsFalse(target.CanRedo);

            // Modify target
            target.Add(100);
            Assert.AreEqual(1, target.Count);
            Assert.AreEqual(100, target[0]);
            Assert.IsTrue (target.CanUndo);
            Assert.IsFalse(target.CanRedo);

            // Undo
            Assert.IsTrue(target.Undo());

            Assert.AreEqual(0, target.Count);
            Assert.IsFalse(target.CanUndo);
            Assert.IsTrue (target.CanRedo);

            // Redo
            Assert.IsTrue(target.Redo());

            Assert.AreEqual(1, target.Count);
            Assert.AreEqual(100, target[0]);
            Assert.IsTrue (target.CanUndo);
            Assert.IsFalse(target.CanRedo);
        }

        [TestMethod]
        public void ActionScopeTest()
        {
            // list which support undo/redo.
            var target = new UndoRedoList<int, List<int>>();
            Assert.IsFalse(target.CanUndo);
            Assert.IsFalse(target.CanRedo);

            // ActionScope
            using (var scope = new UndoRedoList<int, List<int>>.ActionScope(target)) {
                // Modify target in ActionScope
                target.Add(100);
                target.Add(200);
                target.Add(300);
            }

            Assert.AreEqual(3, target.Count);
            Assert.AreEqual(100, target[0]);
            Assert.AreEqual(200, target[1]);
            Assert.AreEqual(300, target[2]);
            Assert.IsTrue(target.CanUndo);

            // Undo
            Assert.IsTrue(target.Undo());
            // The 3 actions in ActionScope can undo in one time.
            Assert.AreEqual(0, target.Count);
            Assert.IsFalse(target.CanUndo);
        }

        [TestMethod]
        public void DisabledUndoScopeTest()
        {
            // list which support undo/redo.
            var target = new UndoRedoList<int, List<int>>();
            Assert.IsFalse(target.CanUndo);
            Assert.IsFalse(target.CanRedo);

            // DisabledUndoScope
            using (var scope = new UndoRedoList<int, List<int>>.DisabledUndoScope(target)) {
                // Modify target in DisabledUndoScope
                target.Add(100);
            }

            // You can't undo actions in DisabledUndoScope.
            Assert.IsFalse(target.CanUndo);
            Assert.IsFalse(target.CanRedo);
        }

        [TestMethod]
        public void UndoRedoListTest()
        {
            // List which support undo/redo.
            var target = new UndoRedoList<int>();

            target.Add(100);

            // You can undo/redo also.
            Assert.IsTrue (target.CanUndo);
            Assert.IsFalse(target.CanRedo);

            Assert.IsTrue(target.Undo());
            Assert.IsTrue(target.Redo());
        }

        [TestMethod]
        public void UndoRedoObservableCollectionTest()
        {
            // ObservableCollection which support undo/redo.
            var target = new UndoRedoObservableCollection<int>();
            target.CollectionChanged += ObservableCollection_CollectionChanged;

            target.Add(100);

            // You can undo/redo also.
            Assert.IsTrue (target.CanUndo);
            Assert.IsFalse(target.CanRedo);

            Assert.IsTrue(target.Undo());
            Assert.IsTrue(target.Redo());

            // event handler
            static void ObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            { /* do domething */ }
        }
    }
}

See also: Shos.UndoRedoList.SampleApp

Author Info

Fujio Kojima: a software developer in Japan

  • Microsoft MVP for Development Tools - Visual C# (Jul. 2005 - Dec. 2014)
  • Microsoft MVP for .NET (Jan. 2015 - Oct. 2015)
  • Microsoft MVP for Visual Studio and Development Technologies (Nov. 2015 - Jun. 2018)
  • Microsoft MVP for Developer Technologies (Nov. 2018 - Jun. 2024)
  • MVP Profile
  • Blog (Japanese)
  • Web Site (Japanese)
  • Twitter
  • Instagram

License

This library is under the MIT License.

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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.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
1.0.5 87 3/28/2024
1.0.4 70 3/26/2024
1.0.3 470 12/10/2020
1.0.2 436 12/9/2020
1.0.1 358 12/8/2020
1.0.0 396 12/8/2020