UnitResult Undo() { if (globallyRepeatableUnits.Count < 1) { throw new InvalidOperationException("No unit to undo."); } IUndoableUnit undoableUnit = globallyUndoableUnits.Pop(); IInternalUnit repeatableUnit = globallyRepeatableUnits.Pop(); var eventArgs = new CancellableUndoServiceEventArgs(undoableUnit); OnUndoing(eventArgs); if (eventArgs.Cancel) { globallyUndoableUnits.AddLast(undoableUnit); globallyRepeatableUnits.AddLast(repeatableUnit); return(UnitResult.Cancelled); } globallyRedoableUnits.AddLast(undoableUnit); UnitResult result = undoableUnit.Undo(); OnUndone(new UndoServiceEventArgs(undoableUnit)); return(result); }
/// <summary> /// Undoes the execution of a previous <see cref="IUnit"/>. /// </summary> /// <exception cref="InvalidOperationException"> /// Occurs if there are no previously executed units to undo.</exception> public UnitResult Undo(object ownerKey) { if (ownerKey == null) { return(Undo()); } if (!undoableDictionary.TryGetValue(ownerKey, out UnitCollection <IUndoableUnit> undoableUnits)) { throw new InvalidOperationException("No undoable units for the specified owner key."); } IUndoableUnit undoableUnit = undoableUnits.Pop(); if (!repeatableDictionary.TryGetValue(ownerKey, out UnitCollection <IInternalUnit> repeatableUnits)) { throw new InvalidOperationException("No repeatable units for the specified owner key."); } repeatableUnits.RemoveLast(); var eventArgs = new CancellableUndoServiceEventArgs(undoableUnit) { OwnerKey = ownerKey }; OnUndoing(eventArgs); if (eventArgs.Cancel) { undoableUnits.AddLast(undoableUnit); return(UnitResult.Cancelled); } if (!redoableDictionary.TryGetValue(ownerKey, out UnitCollection <IUndoableUnit> redoableUnits)) { redoableUnits = new UnitCollection <IUndoableUnit>(); redoableDictionary[ownerKey] = redoableUnits; } redoableUnits.AddLast(undoableUnit); var result = undoableUnit.Undo(); TrimIfRequired(ownerKey); OnUndone(new UndoServiceEventArgs(undoableUnit)); return(result); }
/// <summary> /// Performs the execution of a <see cref="IUnit"/> /// instance that has been undone, then places it back /// into the command stack. /// </summary> public UnitResult Redo(object ownerKey) { if (ownerKey == null) { return(Redo()); } if (!redoableDictionary.TryGetValue(ownerKey, out UnitCollection <IUndoableUnit> redoableUnits)) { throw new InvalidOperationException("No units to be redone for the specified owner key."); } IUndoableUnit unit = redoableUnits.Pop(); var eventArgs = new CancellableUndoServiceEventArgs(unit); OnRedoing(eventArgs); if (eventArgs.Cancel) { redoableUnits.AddLast(unit); return(UnitResult.Cancelled); } var internalUnit = (IInternalUnit)unit; if (!repeatableDictionary.TryGetValue(ownerKey, out UnitCollection <IInternalUnit> repeatableUnits)) { repeatableUnits = new UnitCollection <IInternalUnit>(); } repeatableUnits.AddLast(internalUnit); if (!undoableDictionary.TryGetValue(ownerKey, out UnitCollection <IUndoableUnit> undoableUnits)) { undoableUnits = new UnitCollection <IUndoableUnit>(); } undoableUnits.AddLast(unit); UnitResult result = internalUnit.PerformUnit(internalUnit.Argument, UnitMode.Redo); TrimIfRequired(ownerKey); OnRedone(new UndoServiceEventArgs(unit)); return(result); }