我现在有点糊涂了,我猜我又糊涂了。
我需要实现一个撤消和重做功能的形式。为简单起见,假设我只保存修改过的控件和它离开焦点时的值。
如何保存这些信息,让我可以在"时间轴"中来回移动。
我想过用Stack,但当我在测试我的小演示时,我得了轻微的动脉瘤,所以我在这里。
需要代码,不是真的,但会有帮助。我对我需要实现的算法更感兴趣。有什么建议吗?
是的,您将使用堆栈。有几种方法可以做到;阅读这些参考文献:
http://en.wikipedia.org/wiki/Command_pattern http://en.wikipedia.org/wiki/Memento_pattern
堆栈是完美的,如果你推一个"更改"到它,当撤消弹出一个"更改"。然后将弹出的更改推入代表重做的另一个堆栈。在未来的某个时刻,希望在豁免时,你清除了两个堆栈。
实际上并没有那么简单,因为你需要记录变化的类型,了解新旧值等。所以当你从撤销堆栈弹出时,你弹出的东西必须描述先前的值是什么以及它被设置为哪个控件。
对于重做堆栈来说,它需要了解新值是什么以及它去了哪里。但是,是的,两个堆栈的想法对于自制撤销-重做来说是一个好的开始。
基于业务对象的撤销的一个很好的例子是CSLA。. NET,其中UndoableBase
:
然而,这记录了对象状态的快照,因此它将比基于表单的概念更高级。然而,里昂证券。. NET提供了完整的数据绑定支持,因此从UndoableBase
继承的数据绑定对象自然会在UI中支持撤销(而不是重做)。
我将使用IUndoableAction接口。实现可以存储需要完成和撤消的任何数据。那么,是的,我会使用Stack来保存它们。
interface IUndoableAction
{
void Do();
void Undo();
}
Stack<IUndoableAction> Actions;
每一种操作都将实现Do和Undo方法。
那么,在某个地方会有这两个方法:
void PerformAction(IUndoableActionaction)
{
Actions.Push(action);
action.Do();
}
void Undo()
{
var action = Actions.Pop();
action.Undo();
}
至于在操作类中存储什么,有些操作可以只存储旧值。但是,一旦我有一个操作来交换电子表格中的两行。我没有将每个单元格的值存储在两行中——我只是存储了行下标,以便它们可以交换回来。如果您为每个操作存储所有状态,那么很容易填满大量内存。
那么你也想要一个重做堆栈,当你撤销一个动作时,它被推到重做堆栈。当执行一个新操作时,重做堆栈需要被清除,这样事情就不会乱了序。
最直接的方法可能是撤销/重做堆栈组合。
另一种方法是使用一个操作数组或列表,只对指向数组中索引的指针进行递增/递减操作。当操作撤消时,索引向后移动一个,当操作重新执行时,索引向前移动一个。这样做的好处是,您不需要每个操作都有一个弹出-然后-推送序列。
注意事项:
- 如果您多次撤消,然后执行一个操作,所有的必须取消重做操作。
- 在尝试执行撤销/重做之前,请确保检查边界并确保有可用于撤销/重做的操作。