码迷,mamicode.com
首页 > 其他好文 > 详细

HistoryStack 实现

时间:2015-09-17 19:34:34      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:

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();
        }
    }
}
View Code

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;
        }
    }
View Code
技术分享
        
         public DocumentWorkspace()
        {
...
            History = new HistoryStack();
...
        }
View Code
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();
            }
        }
View Code

 

HistoryStack 实现

标签:

原文地址:http://www.cnblogs.com/cnyou/p/4817135.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!