Skip to main content
RSS feed Subscribe to feed

 

Undoable Lists

Undoable Lists correspond to Undoable Properties, but contain a list of values instead of a single value.

Overview

The framework provides two classes to choose from. It is often convenient to derive from DocumentNodeList<T> to include the standard set of operations:

  • DocumentNodeListBase<T>: Abstract base class for list-like document nodes. It does not expose any public methods to modify the collection, it is up to derived classes to do so.
  • DocumentNodeList<T>: Abstract base class for list-like document nodes. It exposes standard IList<T> methods to modify the collection.

Undoable lists are implemented using balanced binary search trees. The cost of indexing the list is logarithmic to the size of the list, not constant as is usually the case for lists implemented by dynamically resizing arrays. The cost to add or remove an element in the list, regardless of where in the list the element is added or removed, is also logarithmic. Dynamically resizing arrays has a linear time cost.

If you repeatedly index into a list it may be a good idea, for efficiency, to first copy the list into an ordinary list, which provides constant time indexing.

Implementation Pattern

The following example defines a class that implements a list of strings. To keep the class simple, it only has a method to add an element at the end of the list. A real class will usually define a series of operations. The MyCollection class is built in a steps:

  1. Define a Property Name for the property.
  2. Define a private field of type UndoableList<string>.
  3. Create the list using the CreateProperty method.
  4. In the GetObjectData method, serialize the property using the SerializeProperty method.
  5. In the deserialization constructor, deserialize the property using the DeserializeProperty method.
  6. Define public method performing operations, in this case one that adds to the collection.
[Serializable]
public sealed class MyCollection : DocumentNode
{
    public new sealed class PropertyNames : DocumentNode.PropertyNames
    {
        public static PropertyName Items = CreatePropertyName("Items");
    }

    private readonly UndoableList<string> items;

    /// <summary/>
    public MyCollection()
    {
        CreateProperty<string>(PropertyNames.Items, out this.items);
    }

    protected override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);

        SerializeProperty(info, context, this.items);
    }

    internal MyCollection(SerializationInfo info, StreamingContext context) : base(info, context)
    {
        DeserializeProperty(
           info, 
           context, 
           PropertyNames.Items, 
           out this.items);
    }

    public void Add(string item)
    {
        this.items.Add(item);
    }

    // Other methods for operating on lists that you wish to expose follow here.
}