如何在MVVM应用程序中实现撤消/重做?

时间:2010-08-25 16:01:11

标签: silverlight mvvm telerik prism undo-redo

我正在开发一个Silverlight LoB应用程序,设计人员希望它有一个标签界面,类似于Visual Studio界面(我们可能会使用Telerik Rad控件进行对接选项卡)。完成原型后,界面到目前为止运行良好,但我在思考如何在MVVM项目中实现撤消/重做功能时遇到了问题。

撤消/重做功能必须:

  1. 在撤消/重做时,恢复UI状态, 即返回焦点,选择等 控件(如文本框) 这种变化起源于。
  2. 具有按视图撤消/重做堆栈
  3. 通常,我会使用命令模式,但我不确定如何将其应用于MVVM。

    我使用了指挥和绑定以获得理想化的松散耦合视图&视图模型,但它使撤消/重做变得更加棘手,因为视图模型在接收到命令或更改绑定属性时没有任何视图概念和视图状态。似乎我需要某种服务跟踪,只要用户执行一些可撤消操作并获得状态以便以后恢复,哪个视图就处于活动状态。

    对于在MVVM中实现撤消/重做的最佳实践,有什么共识?我非常感兴趣地看看丹尼尔沃恩在他的钙项目中如何做到这一点; Blend显然是使用MVVM模式编写的,它的行为就像我想要我的应用程序一样,如果MS解释他们是如何做到的话会很棒!

2 个答案:

答案 0 :(得分:2)

您需要做的第一件事是确保将操作完全与界面分开。这意味着将影响数据的所有操作转换为离散操作。这也意味着,任何导致视图变化的因素也应记录为离散动作。基本上,接口的状态应该只反映数据更改和基于命令的视图更改(请参阅下面关于视图更改的最后一条注释)。

我们之前使用过的最成功的撤消系统允许嵌套IUndoableCommand对象。这些复合命令汇总为单个用户操作(您希望在撤消菜单中显示的操作类型)。

我注意到你提到跨视图使用撤消...这似乎是一个多形式应用程序的异常行为。通常,撤消仅在单个控件内以及任何拖放操作中。例外通常是基于图形的接口(不是基于表单的)。撤消期间更改表单将等同于MS Word切换到另一个文档并继续撤消...对最终用户来说非常令人不安。可能希望让用户体验的人重新思考设计的这一方面。只差2美分。

希望这有帮助。

答案 1 :(得分:1)

@JamesCo,

我为WPF应用程序实现了undo / redo,最后将我的undo / redo代码发布到http://muf.codeplex.com/。你也可以通过NuGet获得它。只需寻找“MUF”或“Monitored Undo Framework”。它包括对Silverlight 4.0以及.NET 3.5,4.0和WP7的支持。

我的WPF应用程序也使用MVVM,在某些情况下,确实允许撤消选择更改等内容。我还跟踪了WPF框架中显示的活动“页面”,以便用户移回到应该应用撤消操作的页面。

库采用灵活的方法来编写动作以撤消/重做每个步骤。最终,它只需要一个代表撤消和重做代理。你可以让这些代表做你喜欢的事。库中包含一个默认实现,它只接受对象,属性名称,旧值和新值。它构造了基于反射的委托,它将根据需要应用旧值或新值。

就隔离每个视图的更改而言,库允许您为每个“文档”或“容器”保留单独的撤消/重做操作堆栈。您只需传递对容器的引用,以获取关联的撤消/重做堆栈。

最后,该库包括对批量更改的支持。这在多个动作应作为一个单元一起撤消的时候很有用。

欢迎在codeplex网站(http://muf.codeplex.com/)上提出意见和问题。您还可以在那里找到完整的文档和示例应用程序。