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 Listm_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 objects) 30 { 31 m_objects = new List (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 > m_objects = new Dictionary >(); 57 public EditCommandRemove() 58 { 59 } 60 public void AddLayerObjects(ICanvasLayer layer, List 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 m_objects = new List (); 83 UnitPoint m_offset; 84 public EditCommandMove(UnitPoint offset, IEnumerable objects) 85 { 86 m_objects = new List (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 : EditCommandBase106 {107 List m_objects = new List ();108 public EditCommandNodeMove(IEnumerable objects)109 {110 m_objects = new List (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 : EditCommandBase126 {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 UndoRedoBuffer144 {145 List m_undoBuffer = new List ();146 List m_redoBuffer = new List ();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 Dirty158 {159 get { return m_dirty; }160 set { m_dirty = value;}161 }162 public bool CanCapture163 {164 get { return m_canCapture; }165 }166 public bool CanUndo167 {168 get { return m_undoBuffer.Count > 0; }169 }170 public bool CanRedo171 {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 }