Framework / System Layer / Document Object Model / Services / Element History Service

Element History Service
The element history service (or simply history service), is designed to provide elements (and hence documents) with consistent support for Undo and Redo of all operations, which the user or the programmer can possibly perform with an element or element attribute. This service is represented by the NElementHistoryService class. The reason for which the element abstraction has been chosen for base of the history service is that elements can be uniquely identified.
 How it Works

The history service works as a recorder of operations (user or programmer actions). The abstraction of an operation is represented by the NOperation class. All types of operations, which the history service can record must derive from NOperation.

The history service maintains two operations stacks:

  • Undo stack - holds the operations which can be undone
  • Redo stack - holds the operations which can be redone

The history service recording obeys to the following rules:

  • Operations are initially recorded (pushed) in the undo stack. The redo stack is automatically cleared when an operation is recorded in the undo stack.
  • You can undo an operation by calling the Undo method - this will pop the operation from the undo stack and push it in the redo stack.
  • You can redo an operation by calling the Redo method - this will pop the operation from the redo stack and push it in the undo stack.

The history service can virtually operate with an unlimited number of operations. You can however limit the number of recorded undoable operations by setting the MaxUndoLevels property to the number of actions you want the history service to remember:

C#
Copy Code
// instruct the history service to remember the last 200 actions
historyService.MaxUndoLevels = 200;
Visual Basic
Copy Code
' instruct the history service to remember the last 200 actions
historyService.MaxUndoLevels = 200
 Primitive Operations

The Nevron DOM implements a set of primitive operations, which are designed to record any user actions, which can be performed on an element or an element attribute. They can be classified in the following categories:

You can of course implement your own history operations - the only requirement is that they must be derived from the NOperation class.

 

 

 Transactions

Transactions are groups of operations, which are undone and redone as if they were a single operation. Transactions are represented by the NTransaction class (derived from NOperation). The history service provides three methods, which help you easily work with transactions - they are:

  • StartTransaction - opens a new transaction. Internally this creates a new transaction and pushes it in the transactions stack. If there is an opened transaction, the history service will automatically record all operations in it (instead of recording them in the undo stack).
  • Commit - closes the last opened transaction. Internally this method pops the last transaction from the transactions stack and pushes it in the undo stack.
  • Rollback - aborts the last opened transaction. Internally this method pops the last transaction from the transactions stack and undoes all operations, which it contains in reverse order. The rollback method does not record any operation in the undo stack. The effect of rollback is that the object state, which is monitored by the history service is reverted to the state when the transaction was started.

The following code snipped demonstrates a typical transaction based method:

C#
Copy Code
public bool MyTransactionBasedMethod()
{ 
    // start a new transaction 
    historyService.StartTransaction("My transaction");

    try
    { 
  // do something that can fail
  ...
    } 
    catch (Exception ex)
    { 
  // if something went wrong - restore the state as 
  // it was when the transaction was started
  historyService.Rollback();
  return false;
    }

    // if everything went ok - commit the transaction
    historyService.Commit();
    return true;
}
Visual Basic
Copy Code
Public Function MyTransactionBasedMethod() As Boolean 
    ' start a new transaction 
    historyService.StartTransaction("My transaction")

    Try 
  ' do something that can fail
  ... 
    Catch ex As Exception 
  ' if something went wrong - restore the state as 
  ' it was when the transaction was started
  historyService.Rollback()
  Return False
    End Try

    ' if everything went ok - commit the transaction
    historyService.Commit()
    Return True
End Function
 Making Custom Elements and Attributes History Aware

In order to make it easier for you to implement custom elements and attributes, which support history, the NAttribute class and the core INElement implementations found in the respective Nevron product, provide a set of protected methods, which safely call the respective methods of the history service. The following code example demonstrates how to implement a custom history aware attribute:

C#
Copy Code
class MyAttribute : NAttribute
{
    public bool BoolProperty
    {
  get
  {
       return boolField;
  }
  set
  { 
       if (value == boolField)
            return; 
    
          // fire a property changing event and see if the user allows the change 
       // OnPropertyChanging is implemented by NAttribute 
       if (OnPropertyChanging("BoolProperty", value) == false)
            return; 
    
       // record the property value before it is changed 
       // RecordProperty is implemented by NAttribute
       RecordProperty("BoolProperty"); 
       boolField = value; 

       // notify the user that the property has changed
       // OnPropertyChanged is implemented by NAttribute
       OnPropertyChanged("BoolProperty");
  }
    }

    private bool boolField;
}
Visual Basic
Copy Code
Class MyAttribute Inherits NAttribute

    Public Property BoolProperty() As Boolean
  Get 
       Return boolField 
  End Get 
  Set(ByVal Value As Boolean)
       If Value = boolField Then 
            Return 
       End If 

            ' fire a property changing event and see if the user allows the change 
       ' OnPropertyChanging is implemented by NAttribute 
       If OnPropertyChanging("BoolProperty", Value) = False Then 
            Return 
       End If 
   
       ' record the property value before it is changed 
       ' RecordProperty is implemented by NAttribute
       RecordProperty("BoolProperty") 
       boolField = Value 
            
         ' notify the user that the property has changed
       ' OnPropertyChanged is implemented by NAttribute
       OnPropertyChanged("BoolProperty")
  End Set
    End Property

    Private boolField As Boolean
End Class
See Also