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 }