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