Skip to content

Manage edit session

This operation is the framework's n-level undo workflow for business objects and business collections. It lets a caller open an edit scope, mutate object state freely in memory, and then either commit that state as the new baseline or roll it back to the last snapshot — while child objects, child collections, and deleted-item lists stay synchronized with the parent at every level.

Field Value
Operation ID OP-CORE-001
Trigger Caller or data binding invokes BeginEdit, CancelEdit, ApplyEdit, IEditableObject.BeginEdit, IEditableObject.CancelEdit, or IEditableObject.EndEdit.
Inputs Current business object or collection graph, including child objects, child collections, and deleted children.
Outputs Snapshot added, restored, or discarded; child add/delete state reconciled.
Primary components clsBusinessBase.BeginEdit, clsBusinessBase.CancelEdit, clsBusinessBase.ApplyEdit, clsBusinessCollectionBase.BeginEdit, clsBusinessCollectionBase.CancelEdit, clsBusinessCollectionBase.ApplyEdit, clsUndoableBase.CopyState, clsUndoableBase.UndoChanges, clsUndoableBase.AcceptChanges
Entry point SAIF.Framework.Core\V1\BaseItems\clsBusinessBase.vb

Steps

  1. Start the edit scope by calling BeginEdit on a business object or collection.
  2. clsBusinessBase.BeginEdit marks the object as being in a binding edit and calls CopyState.
  3. clsBusinessCollectionBase.BeginEdit calls CopyState for the collection and its children.
  4. Capture the current in-memory state in clsUndoableBase.CopyState.
  5. The method reflects over instance fields, skips fields marked with NotUndoable, and separates child objects/collections from scalar state.
  6. For each child clsBusinessBase or clsBusinessCollectionBase, it cascades CopyState() so the full object graph participates in the same edit level.
  7. For ordinary fields, it stores <DeclaringType>!<FieldName> keys and field values in a hashtable.
  8. Before serialization, it raises serialization-notification hooks for captured state; it then serializes the hashtable into the state stack.
  9. Cancel the edit scope by calling CancelEdit when changes should be rolled back.
  10. clsBusinessBase.CancelEdit clears the binding-edit flag, calls UndoChanges(), re-registers rules through AddBusinessRules(), and raises OnIsModifiedChanged().
  11. clsBusinessCollectionBase.CancelEdit calls UndoChanges() and then re-runs AddBusinessRules() for both current children and deleted children.
  12. Restore the last snapshot in UndoChanges.
  13. clsUndoableBase.UndoChanges pops the latest serialized snapshot, deserializes it, and restores ordinary field values.
  14. For child objects and child collections, it cascades UndoChanges() instead of replacing references directly.
  15. Collection UndoChanges decrements the collection edit level, removes items that were added below the restored level, and moves rolled-back deleted children back into the live list when their delete flag clears.
  16. If data binding cancels a brand-new child before it is ever committed, IEditableObject.CancelEdit removes that child from its parent collection entirely.
  17. Commit the edit scope by calling ApplyEdit when changes should become the new baseline.
  18. clsBusinessBase.ApplyEdit clears the binding-edit flag, marks the object as committed, and calls AcceptChanges().
  19. clsBusinessCollectionBase.ApplyEdit calls AcceptChanges() for the collection graph.
  20. Remove the most recent snapshot in AcceptChanges.
  21. clsUndoableBase.AcceptChanges pops the latest state-stack entry.
  22. It then cascades AcceptChanges() through child objects and child collections so every participant discards the same edit level.

Process flow

The following diagram visualizes this operation's control flow.

flowchart TD
    Start([BeginEdit]) --> Copy[Copy current state]
    Copy --> Change[Caller changes object graph]
    Change --> D{Commit or cancel?}
    D -->|Cancel| Undo[UndoChanges and rebuild rules]
    D -->|Apply| Accept[AcceptChanges]
    Undo --> EndUndo([State restored])
    Accept --> EndOk([State committed])

Failure and edge-case behavior

  • Repeated IEditableObject.CancelEdit or IEditableObject.EndEdit calls are no-ops once m_BindingEdit is no longer active, so double-cancel from data-binding infrastructure cannot corrupt state.
  • Canceling a brand-new bound child removes it from the parent collection entirely when rollback returns below the level at which it was added — the child never existed as far as the committed graph is concerned.
  • Fields marked NotUndoable are excluded from every snapshot, so undo never restores them; callers relying on undo for those fields will not see the expected rollback.

Sources

  • SAIF.Framework.Core\V1\BaseItems\clsBusinessBase.vb
  • SAIF.Framework.Core\V1\BaseItems\clsBusinessCollectionBase.vb
  • SAIF.Framework.Core\V1\BaseItems\clsUndoableBase.vb