Undo

1.  redo和undo的实现
  知道执行了什么命令,影响了那些数据
  终止条件和状态

2.  这里我犯了个错误,其实我根本不需要知道是执行的什么命令,对于绘图系统,我只需知道对数据产生了那些影响。撤销和重做其实都是针对数据(几何对象)来说的。

所有这里只需要在操作(添加几何对象、删除几何对象、修改几何对象、增加节点、删除节点、移动节点等)时另外引一条线,就是UndoRedoBuffer对象,他是一个List,其实如果是栈则更好,用它记录操作影响的数据。注意是操作影响的数据,和上面所说的操作是两个概念。

抽象了一个操作影响数据的EditCommandBase类,具体子类有:添加影响数据类,删除影响数据类、移动影响数据类。

在每一次修改Canvas对象的几何对象集合时都要引出一条线,记录这个操作影响数据信息,即加入UndoRedoBuffer。

Undo就是UndoRedoBuffer顶部的影响数据修改几何对象集合,实现回退。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 using System.Drawing;
  5 
  6 namespace Canvas
  7 {
  8     class EditCommandBase
  9     {
 10         public virtual bool DoUndo(IModel data)
 11         {
 12             return false;
 13         }
 14         public virtual bool DoRedo(IModel data)
 15         {
 16             return false;
 17         }
 18     }
 19     class EditCommandAdd : EditCommandBase
 20     {
 21         List<IDrawObject> m_objects = null;
 22         IDrawObject m_object;
 23         ICanvasLayer m_layer;
 24         public EditCommandAdd(ICanvasLayer layer, IDrawObject obj)
 25         {
 26             m_object = obj;
 27             m_layer = layer;
 28         }
 29         public EditCommandAdd(ICanvasLayer layer, List<IDrawObject> objects)
 30         {
 31             m_objects = new List<IDrawObject>(objects);
 32             m_layer = layer;
 33         }
 34         public override bool DoUndo(IModel data)
 35         {
 36             if (m_object != null)
 37                 data.DeleteObjects(new IDrawObject[] { m_object });
 38             if (m_objects != null)
 39                 data.DeleteObjects(m_objects);
 40             return true;
 41         }
 42         public override bool DoRedo(IModel data)
 43         {
 44             if (m_object != null)
 45                 data.AddObject(m_layer, m_object);
 46             if (m_objects != null)
 47             {
 48                 foreach (IDrawObject obj in m_objects)
 49                     data.AddObject(m_layer, obj);
 50             }
 51             return true;
 52         }
 53     }
 54     class EditCommandRemove : EditCommandBase
 55     {
 56         Dictionary<ICanvasLayer, List<IDrawObject>> m_objects = new Dictionary<ICanvasLayer, List<IDrawObject>>();
 57         public EditCommandRemove()
 58         {
 59         }
 60         public void AddLayerObjects(ICanvasLayer layer, List<IDrawObject> objects)
 61         {
 62             m_objects.Add(layer, objects);
 63         }
 64         public override bool DoUndo(IModel data)
 65         {
 66             foreach (ICanvasLayer layer in m_objects.Keys)
 67             {
 68                 foreach (IDrawObject obj in m_objects[layer])
 69                     data.AddObject(layer, obj);
 70             }
 71             return true;
 72         }
 73         public override bool DoRedo(IModel data)
 74         {
 75             foreach (ICanvasLayer layer in m_objects.Keys)
 76                 data.DeleteObjects(m_objects[layer]);
 77             return true;
 78         }
 79     }
 80     class EditCommandMove : EditCommandBase
 81     {
 82         List<IDrawObject> m_objects = new List<IDrawObject>();
 83         UnitPoint m_offset;
 84         public EditCommandMove(UnitPoint offset, IEnumerable<IDrawObject> objects)
 85         {
 86             m_objects = new List<IDrawObject>(objects);
 87             m_offset = offset;
 88         }
 89         public override bool DoUndo(IModel data)
 90         {
 91             foreach (IDrawObject obj in m_objects)
 92             {
 93                 UnitPoint offset = new UnitPoint(-m_offset.X, -m_offset.Y);
 94                 obj.Move(offset);
 95             }
 96             return true;
 97         }
 98         public override bool DoRedo(IModel data)
 99         {
100             foreach (IDrawObject obj in m_objects)
101                 obj.Move(m_offset);
102             return true;
103         }
104     }
105     class EditCommandNodeMove : EditCommandBase
106     {
107         List<INodePoint> m_objects = new List<INodePoint>();
108         public EditCommandNodeMove(IEnumerable<INodePoint> objects)
109         {
110             m_objects = new List<INodePoint>(objects);
111         }
112         public override bool DoUndo(IModel data)
113         {
114             foreach (INodePoint obj in m_objects)
115                 obj.Undo();
116             return true;
117         }
118         public override bool DoRedo(IModel data)
119         {
120             foreach (INodePoint obj in m_objects)
121                 obj.Redo();
122             return true;
123         }
124     }
125     class EditCommandEditTool : EditCommandBase
126     {
127         IEditTool m_tool;
128         public EditCommandEditTool(IEditTool tool)
129         {
130             m_tool = tool;
131         }
132         public override bool DoUndo(IModel data)
133         {
134             m_tool.Undo();
135             return true;
136         }
137         public override bool DoRedo(IModel data)
138         {
139             m_tool.Redo();
140             return true;
141         }
142     }
143     class UndoRedoBuffer
144     {
145         List<EditCommandBase> m_undoBuffer = new List<EditCommandBase>();
146         List<EditCommandBase> m_redoBuffer = new List<EditCommandBase>();
147         bool m_canCapture = true;
148         bool m_dirty = false;
149         public UndoRedoBuffer()
150         {
151         }
152         public void Clear()
153         {
154             m_undoBuffer.Clear();
155             m_redoBuffer.Clear();
156         }
157         public bool Dirty
158         {
159             get { return m_dirty; }
160             set { m_dirty = value;}
161         }
162         public bool CanCapture
163         {
164             get { return m_canCapture; }
165         }
166         public bool CanUndo
167         {
168             get { return m_undoBuffer.Count > 0; }
169         }
170         public bool CanRedo
171         {
172             get { return m_redoBuffer.Count > 0; }
173         }
174         public void AddCommand(EditCommandBase command)
175         {
176             if (m_canCapture && command != null)
177             {
178                 m_undoBuffer.Add(command);
179                 m_redoBuffer.Clear();
180                 Dirty = true;
181             }
182         }
183         public bool DoUndo(IModel data)
184         {
185             if (m_undoBuffer.Count == 0)
186                 return false;
187             m_canCapture = false;
188             EditCommandBase command = m_undoBuffer[m_undoBuffer.Count - 1];
189             bool result = command.DoUndo(data);
190             m_undoBuffer.RemoveAt(m_undoBuffer.Count - 1);
191             m_redoBuffer.Add(command);
192             m_canCapture = true;
193             Dirty = true;
194             return result;
195         }
196         public bool DoRedo(IModel data)
197         {
198             if (m_redoBuffer.Count == 0)
199                 return false;
200             m_canCapture = false;
201             EditCommandBase command = m_redoBuffer[m_redoBuffer.Count - 1];
202             bool result = command.DoRedo(data);
203             m_redoBuffer.RemoveAt(m_redoBuffer.Count - 1);
204             m_undoBuffer.Add(command);
205             m_canCapture = true;
206             Dirty = true;
207             return result;
208         }
209     }
210 }

 

原文地址:https://www.cnblogs.com/yhlx125/p/3224979.html