2010-12-02 54 views
3

我已经做了一些研究,以了解如何实现这个问题的标题。我正在开发的应用程序已经开发了几年左右(尽管进展缓慢,你们都知道它是如何在真实世界中)。现在我需要放入撤销/重做多级功能。现在说“在开始之前你应该考虑过这个问题”有点晚了......呃,我们确实考虑过这个问题 - 而且我们对此没有采取任何措施,现在就是这样。从摸索SO(和外部链接),我可以看到,这两个最常见的方法似乎是...在已经功能的应用程序中撤消WPF/C#中的重做

Command Pattern

Memento Pattern

Command模式看起来这将是一个地狱很多工作,我只能想象它会在这个过程中抛出成千上万的错误,所以我并不喜欢那个。

Memento模式实际上很像我在我脑中为此所做的。我正在考虑是否有办法快速获取当前内存中的对象模型的快照,然后我可以将它存储在某处(也可能存储在内存中,也可能存储在文件中)。这似乎是一个好主意,我能看到的唯一问题就是它如何与我们已经写过的内容整合。您可以看到应用程序,因为它可以在大面板中绘制图像(可能有数百个),然后允许用户通过UI或通过自定义构建的属性网格来操作它们。整个应用程序与大观察员模式相关联。第二件事情发生了变化,事件被解雇了,所有需要更新的事情都发生了。这很好,但我不能帮助你想,如果用户在属性网格中输入文本到texfield,那么在用户界面赶上之前会有一点延迟(看起来每次用户按下一个键时都会添加一个新的快照到撤消列表)。所以我对你的问题是......

  • 你知道任何可以替代Memento模式,可能工作。
  • 您是否认为Memento模式适合这里,或者它会让应用程序的速度变慢。
  • 如果Memento模式是要走的路,那么创建对象模型快照的最有效方法是什么(我在想连载它或什么)
  • 如果快照存储在内存中或者是否可能把它们放到文件中?

如果你有这么多,谢谢你的阅读。你有任何输入将是有价值的,非常感谢。

回答

1

为撤销/重做关键的事情是

  • 知道你需要什么样的状态保存和恢复
  • 知道什么时候你需要保存状态

添加撤消/后重做事实上总是一件痛苦的事情 - (我知道这个评论现在对你来说毫无用处,但最好在开始之前为应用程序框架设计支持,因为它有助于人们在整个开发过程中使用对友好的模式)。

也许最简单的方法将是一个纪念基于一个:

  • 找到所有这些都是你的“文件”中的数据。你能否以某种方式统一这些数据,从而形成一个连贯的整体?通常,如果你可以将你的文档结构串行化为一个文件,你需要的逻辑就是在序列化系统中,这样可以给你一个方法。直接使用它的缺点通常是你通常必须序列化所有的东西,将是巨大而缓慢的。如果可能的话,重构代码以便(a)在整个应用程序中使用通用的序列化接口(因此可以使用通用调用来保存/恢复数据的任何部分),以及(b)每个子系统都被封装所以对数据的修改必须经过一个通用的接口(而不是许多人直接修改成员变量,他们都应该调用由对象提供的API来请求对其自身进行修改),以及(c)部分数据保留“版本号”。每次进行更改(通过(b)中的界面),都应该增加该版本号。这种方法意味着您现在可以扫描整个文档并使用版本号查找自上次查看以来发生更改的部分,然后将最小数量序列化以保存并恢复更改后的状态。

    • 提供一种可以记录单个撤销步骤的机制。这意味着允许多重系统对数据结构进行更改,然后在更新所有内容时触发撤消记录。确定何时执行此操作可能会非常棘手,但通常可以通过在您的UI完成处理每个输入事件后,扫描文档以查看消息循环中的更改(请参阅上文)来完成。

除此之外,我建议去一个命令为基础的方法,因为有很多好处,它除了撤销/重做。

5

嗯,这是我对这个问题的想法。

1-您需要多级撤销/重做功能。因此您需要存储可以存储在堆栈中的用户操作。

2-你的第二个问题如何确定什么被我认为通过Memento模式的操作所改变,这是一个相当大的挑战。纪念是关于在你的记忆中摧毁最初的对象状态。

要么你需要存储操作所改变的内容,以便你可以使用这些信息来撤销操作。

命令模式是为撤销/重做功能而设计的,我会说它的后期但它的价值,同时实现了多年来使用的设计,并且适用于大多数应用程序。

+1

+1当你说撤销/重做你自动说命令模式。无论简单还是难以实施。 – 2010-12-02 18:16:03

+0

目前的应用程序完全与观察员联系。让应用程序创建一个“纪念品”就像编写函数来创建它,然后订阅看守人到所需的观察者一样简单。我没有把心放在纪念品上,但我倾向于它。否则我会很高兴地相信。 – DrLazer 2010-12-02 18:28:20

3

如果性能允许,您可以在每次操作之前序列化您的域。如果对象本身不大,几百个对象就不多了。

由于您的对象图可能不是微不足道的(即使用继承,循环,...)集成的XmlSerializer和JsonSerializers是没有问题的。 Json.net支持这些,但是对某些类型(本地日期时间,数字...)进行一些有损转换,所以它也不好。

我认为protobuf序列化器需要某种形式的DTD(.proto文件)或装饰所有属性的属性将它们的名称映射到一个数字,因此它可能不是最优的。

BinaryFormatter可以序列化大多数东西,你只需要用[Serializable]属性来修饰所有的类。但我自己并没有使用它,所以可能会有我不知道的陷阱。也许与单身人士或事件有关。

+0

我当时希望情况会如此。使用Memento模式并以某种序列化状态保存对象模型。你知道一个快速的方法来做这样的事情吗? – DrLazer 2010-12-02 19:04:09

1

您可能会发现“受监视的撤消框架”非常有用。 http://muf.codeplex.com/

它使用类似于备忘录模式的方式,通过在发生变化时监视更改并允许您将委托放置在将撤消/重做更改的撤消堆栈上。

我考虑过一种可以序列化/反序列化文档但是担心开销的方法。相反,我通过物业基地来监控房产模型(或视图模型)的变化。然后,根据需要,我使用MUF库对相关更改进行“批处理”,以便它们以撤销/重做为单位进行更改。

事实上,你有你的UI设置来对底层模型的变化作出反应是很好的。这听起来像是你可以在那里注入撤销/重做逻辑,并且这些改变会向用户界面发起泡沫。

我不认为你会看到很多滞后或性能下降。我有一个类似的应用程序,我们根据模型中的数据绘制了一个图表。迄今为止,我们已经取得了不错的成绩。

你可以在codeplex网站上找到更多的信息和文档在http://muf.codeplex.com/。该库也可以通过NuGet获得,支持.NET 3.5,4.0,SL4和WP7。

相关问题