/// <summary> /// Ends a batch of undoable operations. /// </summary> /// <param name="rollback">Set to true if the batch needs to be undone immediately.</param> /// <returns></returns> public int EndBatch(bool rollback = false) { if (!Enabled) { return(0); } if (inProgress) { return(0); } if (batchDepth == 0) { throw new InvalidOperationException("EndBatch() called before BeginBatch()."); } batchDepth--; if ((_UndoStack.Peek() as UndoBatchAction)?.Begin ?? false) { // If the last action on the stack is a begin-BatchAction, it means no actions was performed // in this batch. Pop the last BatchAction to avoid having an empty batch on the stack. var a = _UndoStack.Pop() as UndoBatchAction; if (!a.Begin) { throw new InvalidOperationException(); // should not happen } return(0); } else if ((_UndoStack.Skip(1).FirstOrDefault() as UndoBatchAction)?.Begin ?? false) { // If the batch action only contains a single non-batch action, we might as well pop the batch // and add the non-batch action directly to the stack: var a = _UndoStack.Pop(); var beginBatch = _UndoStack.Pop(); _UndoStack.Push(a); } else { var actionName = _UndoStack.OfType <UndoBatchAction>().First(uba => uba.Depth == batchDepth).ActionName; _UndoStack.Push(new UndoBatchAction(actionName, batchDepth, false)); } // Rollback if requested: if (rollback) { XDo(false, false); return(0); } UndoStateChanged?.Invoke(this, new EventArgs()); return(batchSizeCounter); }
/// <summary> /// Call this method when an action is performed, that should be undoable /// </summary> /// <param name="action"></param> internal void Add(IUndoAction action) { if (!Enabled) { return; } if (inProgress) { return; } _UndoStack.Push(action); if (CanRedo) { _RedoStack.Clear(); } batchSizeCounter++; if (!(action is UndoBatchAction) && batchDepth == 0) { UndoStateChanged?.Invoke(this, new EventArgs()); } }
internal void XDo(bool redo, bool inversable) { if (!Enabled) { throw new InvalidOperationException("UndoManager is not enabled."); } //if (undoDepth == -1 && batchDepth != 0) throw new InvalidOperationException("Cannot undo/redo while a batch is in progress."); _handler.BeginUpdate(null); var stack = redo ? _RedoStack : _UndoStack; var inverseStack = redo ? _UndoStack : _RedoStack; if (stack.Count > 0) { inProgress = true; IsRedoing = redo; IsUndoing = !IsRedoing; var item = stack.Pop(); if (redo) { item.Redo(); } else { item.Undo(); } if (inversable) { inverseStack.Push(item); } if (item is UndoBatchAction) { var batchDepth = (item as UndoBatchAction).Depth; do { item = stack.Pop(); if (redo) { item.Redo(); } else { item.Undo(); } if (inversable) { inverseStack.Push(item); } }while (!(item is UndoBatchAction) || (item as UndoBatchAction).Depth > batchDepth); } IsRedoing = false; IsUndoing = false; inProgress = false; } UndoStateChanged?.Invoke(this, new EventArgs()); _handler.EndUpdate(false); }