HistoryStack 实现

using System;
using System.Collections.Generic;
using ChenXi.Framework.UIBase;

namespace ChenXi.QD2013
{
    /// <summary>
    /// 历史记录,保存撒消与恢复列表
    /// </summary>
    [Serializable]
    public class HistoryStack
    {
        private int _isExecutingMemento; // 0 -> false, >0 -> true
        private int _stepGroupDepth;

        public HistoryStack()
        {
            UndoStack = new List<HistoryMemento>();
            RedoStack = new List<HistoryMemento>();
        }

        public HistoryStack(
            List<HistoryMemento> undoStack,
            List<HistoryMemento> redoStack)
        {
            UndoStack = new List<HistoryMemento>(undoStack);
            RedoStack = new List<HistoryMemento>(redoStack);
        }

        public bool IsExecutingMemento
        {
            get { return _isExecutingMemento > 0; }
        }

        public List<HistoryMemento> UndoStack { get; private set; }
        public List<HistoryMemento> RedoStack { get; private set; }

        private void PushExecutingMemento()
        {
            ++_isExecutingMemento;
        }

        private void PopExecutingMemento()
        {
            --_isExecutingMemento;
        }

        public void BeginStepGroup()
        {
            ++_stepGroupDepth;
        }

        public void EndStepGroup()
        {
            --_stepGroupDepth;

            if (_stepGroupDepth == 0)
            {
                OnFinishedStepGroup();
            }
        }

        public event EventHandler FinishedStepGroup;

        protected void OnFinishedStepGroup()
        {
            if (FinishedStepGroup != null)
            {
                FinishedStepGroup(this, EventArgs.Empty);
            }
        }

        public event EventHandler SteppedBackward;

        protected void OnSteppedBackward()
        {
            if (SteppedBackward != null)
            {
                SteppedBackward(this, EventArgs.Empty);
            }
        }

        public event EventHandler SteppedForward;

        protected void OnSteppedForward()
        {
            if (SteppedForward != null)
            {
                SteppedForward(this, EventArgs.Empty);
            }
        }

        /// <summary>
        ///     Event handler for when a new history memento has been added.
        /// </summary>
        public event EventHandler NewHistoryMemento;

        protected void OnNewHistoryMemento()
        {
            if (NewHistoryMemento != null)
            {
                NewHistoryMemento(this, EventArgs.Empty);
            }
        }

        /// <summary>
        ///     Event handler for when changes have been made to the history.
        /// </summary>
        public event EventHandler Changed;

        protected void OnChanged()
        {
            if (Changed != null)
            {
                Changed(this, EventArgs.Empty);
            }
        }

        public event EventHandler Changing;

        protected void OnChanging()
        {
            if (Changing != null)
            {
                Changing(this, EventArgs.Empty);
            }
        }

        public event EventHandler HistoryFlushed;

        protected void OnHistoryFlushed()
        {
            if (HistoryFlushed != null)
            {
                HistoryFlushed(this, EventArgs.Empty);
            }
        }

        public event ExecutingHistoryMementoEventHandler ExecutingHistoryMemento;

        protected void OnExecutingHistoryMemento(ExecutingHistoryMementoEventArgs e)
        {
            if (ExecutingHistoryMemento != null)
            {
                ExecutingHistoryMemento(this, e);
            }
        }

        public event ExecutedHistoryMementoEventHandler ExecutedHistoryMemento;

        protected void OnExecutedHistoryMemento(ExecutedHistoryMementoEventArgs e)
        {
            if (ExecutedHistoryMemento != null)
            {
                ExecutedHistoryMemento(this, e);
            }
        }

        public void PerformChanged()
        {
            OnChanged();
        }

        /// <summary>
        /// 压入新的操作
        /// </summary>
        /// <param name="value"></param>
        public void PushNewMemento(HistoryMemento value)
        {
            Utility.GCFullCollect();

            OnChanging();

            ClearRedoStack();
            UndoStack.Add(value);
            OnNewHistoryMemento();

            OnChanged();

            value.Flush();
            Utility.GCFullCollect();
        }

        /// <summary>
        /// 单步恢复
        /// </summary>
        public void StepForward()
        {
            PushExecutingMemento();

            try
            {
                StepForwardImpl();
            }

            finally
            {
                PopExecutingMemento();
            }
        }

        private void StepForwardImpl()
        {
            var topMemento = RedoStack[0];

            OnChanging();

            var ehaea1 = new ExecutingHistoryMementoEventArgs(topMemento, true, false);

            if (topMemento.SeriesGuid != Guid.Empty)
            {
                ehaea1.SuspendTool = true;
            }

            OnExecutingHistoryMemento(ehaea1);

            var redoMemento = RedoStack[0];

            // Possibly useful invariant here:
            //     ehaea1.HistoryMemento.SeriesGuid == ehaea2.HistoryMemento.SeriesGuid == ehaea3.HistoryMemento.SeriesGuid
            var ehaea2 = new ExecutingHistoryMementoEventArgs(redoMemento, false, ehaea1.SuspendTool);
            OnExecutingHistoryMemento(ehaea2);

            var undoMemento = redoMemento.PerformUndo();

            RedoStack.RemoveAt(0);
            UndoStack.Add(undoMemento);

            var ehaea3 = new ExecutedHistoryMementoEventArgs(undoMemento);
            OnExecutedHistoryMemento(ehaea3);

            OnChanged();
            OnSteppedForward();

            undoMemento.Flush();

            if (_stepGroupDepth == 0)
            {
                OnFinishedStepGroup();
            }
        }

        /// <summary>
        /// 单步撒消
        /// </summary>
        public void StepBackward()
        {
            PushExecutingMemento();

            try
            {
                StepBackwardImpl();
            }

            finally
            {
                PopExecutingMemento();
            }
        }

        public HistoryMemento TopRedo
        {
            get { return RedoStack.Count > 0 ? RedoStack[0] : null; }
        }

        public HistoryMemento TopUndo
        {
            get { return UndoStack.Count > 0 ? UndoStack[UndoStack.Count - 1] : null; }
        }

        private void StepBackwardImpl()
        {
            var topMemento = UndoStack[UndoStack.Count - 1];
            {
                OnChanging();

                var ehaea1 = new ExecutingHistoryMementoEventArgs(topMemento, true, false);

                if (topMemento.SeriesGuid == Guid.Empty)
                {
                    ehaea1.SuspendTool = true;
                }

                OnExecutingHistoryMemento(ehaea1);

                var undoMemento = UndoStack[UndoStack.Count - 1];

                var ehaea2 = new ExecutingHistoryMementoEventArgs(undoMemento, false, ehaea1.SuspendTool);
                OnExecutingHistoryMemento(ehaea2);

                var redoMemento = UndoStack[UndoStack.Count - 1].PerformUndo();
                UndoStack.RemoveAt(UndoStack.Count - 1);
                RedoStack.Insert(0, redoMemento);

                // Possibly useful invariant here:
                //     ehaea1.HistoryMemento.SeriesGuid == ehaea2.HistoryMemento.SeriesGuid == ehaea3.HistoryMemento.SeriesGuid
                var ehaea3 = new ExecutedHistoryMementoEventArgs(redoMemento);
                OnExecutedHistoryMemento(ehaea3);

                OnChanged();
                OnSteppedBackward();

                redoMemento.Flush();

            }

            if (_stepGroupDepth == 0)
            {
                OnFinishedStepGroup();
            }
        }

        public void ClearAll()
        {
            OnChanging();

            foreach (var ha in UndoStack)
            {
                ha.Flush();
            }

            foreach (var ha in RedoStack)
            {
                ha.Flush();
            }

            UndoStack = new List<HistoryMemento>();
            RedoStack = new List<HistoryMemento>();
            OnChanged();
            OnHistoryFlushed();
        }

        public void ClearRedoStack()
        {
            foreach (var ha in RedoStack)
            {
                ha.Flush();
            }

            OnChanging();
            RedoStack = new List<HistoryMemento>();
            OnChanged();
        }
    }
}

HistoryMemento 历史备忘录基类

    /// <summary>
    /// 历史备忘录基类
    /// </summary>
    public abstract class HistoryMemento
    {
        private static int nextId;
        protected int id;
        private Guid seriesGuid = Guid.Empty;

        public HistoryMemento(string name)
        {
            Name = name;
            id = Interlocked.Increment(ref nextId);
        }

        public string Name { get; set; }

        public int ID
        {
            get { return id; }

            set { id = value; }
        }

        public Guid SeriesGuid
        {
            get { return seriesGuid; }

            set { seriesGuid = value; }
        }

        /// <summary>
        ///     Ensures that the memory held by the _clipData property is serialized to disk and
        ///     freed from memory.
        /// </summary>
        public void Flush()
        {

            OnFlush();
        }

        protected virtual void OnFlush()
        {
        }

        /// <summary>
        ///     This will perform the necessary work required to undo an action.
        ///     Note that the returned HistoryMemento should have the same ID.
        /// </summary>
        /// <returns>
        ///     Returns a HistoryMemento that can be used to redo the action.
        ///     Note that this property should hold: undoAction = undoAction.PerformUndo().PerformUndo()
        /// </returns>
        protected abstract HistoryMemento OnUndo();

        /// <summary>
        ///     This method ensures that the returned HistoryMemento has the appropriate ID tag.
        /// </summary>
        /// <returns>
        ///     Returns a HistoryMemento that can be used to redo the action.
        ///     The ID of this HistoryMemento will be the same as the object that this
        ///     method was called on.
        /// </returns>
        public HistoryMemento PerformUndo()
        {
            var ha = OnUndo();
            ha.ID = ID;
            ha.SeriesGuid = SeriesGuid;
            return ha;
        }
    }

         public DocumentWorkspace()
        {
...
            History = new HistoryStack();
...
        }

UnDo / RoDo

        /// <summary>
        /// 撤销、回退一步
        /// </summary>
        public void UnDo()
        {
            if (History.UndoStack.Count > 0)
            {
                if (!(History.UndoStack[History.UndoStack.Count - 1] is NullHistoryMemento))
                {
                    using (new WaitCursorChanger(FindForm()))
                    {
                        History.StepBackward();
                        RefreshView();
                        Update();
                    }
                }

                Utility.GCFullCollect();
            }
        }

        /// <summary>
        /// 恢复、前进一步
        /// </summary>
        public void ReDo()
        {
            if (History.RedoStack.Count > 0)
            {
                if (
                    !(History.RedoStack[History.RedoStack.Count - 1] is
                        NullHistoryMemento))
                {
                    using (new WaitCursorChanger(FindForm()))
                    {
                        History.StepForward();
                        RefreshView();
                        Update();
                    }
                }

                Utility.GCFullCollect();
            }
        }

时间: 2024-10-27 12:08:14

HistoryStack 实现的相关文章

从零开始开发Android版2048 (五) 撤销的实现

本篇的内容是,在前一篇的基础上加入了撤销的功能.撤销其实就是将当前的用户界面恢复到这次滑动值前的样子.我实现撤销的主要原理是,将每次滑动后界面上的格子和对应的数字记录下来,当然还有分数,把这些数据写入一个栈中,然后点击撤销操作的时候,将栈顶pop掉,读取下一个栈中的对象,并根据对象中存储的数据重新绘制界面. 下面是我用于存储每次界面情况的类,在这个类中保存了界面中主要的三个数据,空白格.数字格和当前的分数. package com.example.t2048; import java.util.

Activity、Task、Application关系+Intent启动Flag

什么是Android  Application? 简单来说,一个apk文件就是一个Application. 任何一个AndroidApplication基本上是由一些Activities组成,当用户与应用程序交互时其所包含的部分Activities具有紧密的逻辑关系,或者各自独立处理不同的响应. 这些Activities捆绑在一起成为了一个处理特定需求的Application,并且以".apk"作为后缀名存在于文件系统中. Android平台默认下的应用程序 例如:Email.Cale

模拟window的history对象

window的history是历史条目对象,在浏览器里,历史条目是保存在一个历史记录栈里,并通过go()等一系列函数进行操作. 最近遇到一个项目,主要需求是HTML页面放到App里,App包含一个webView来显示HTML,并提供两个按钮,一个关闭按钮(关闭webView并返回app其他界面),一个是后退按钮,后退页面,也就是浏览器的后退按钮.需求要求所有页面不能跳转,也就是需要通过div的切换来模拟多个页面. 如此原生的history对象我们就不能用了,但是借鉴原理设计一个自己的历史记录栈还

javascript基础修炼(6)——前端路由的基本原理

[造轮子]是笔者学习和理解一些较复杂的代码结构时的常用方法,它很慢,但是效果却胜过你读十几篇相关的文章.为已知的API方法自行编写实现,遇到自己无法复现的部分再有针对性地去查资料,最后当你再去学习官方代码的时候,就会明白这样做的价值,总有一天,你也将有能力写出大师级的代码. 一. 前端路由 现代前端开发中最流行的页面模型,莫过于SPA单页应用架构.单页面应用指的是应用只有一个主页面,通过动态替换DOM内容并同步修改url地址,来模拟多页应用的效果,切换页面的功能直接由前台脚本来完成,而不是由后端