Example #1
0
        /// <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);
        }
Example #2
0
        /// <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());
            }
        }
Example #3
0
        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);
        }