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

5
我正在开发一个Silverlight LoB应用程序,设计师想要一个类似于Visual Studio的选项卡界面(我们可能会使用Telerik Rad控件来停靠选项卡)。经过原型测试,界面目前运行良好,但我在思考如何在MVVM项目中实现撤销/重做功能时遇到了问题。
撤销/重做功能必须:
1. 在撤销/重做时,恢复UI状态,即将焦点、选择等返回到更改源(例如文本框)的控件。 2. 拥有每个视图的撤销/重做堆栈。
通常,我会使用命令模式,但我不确定如何在MVVM中应用它。
我已经使用命令和绑定来获得理想的视图和视图模型的松耦合,但这使得撤销/重做变得更加棘手,因为视图模型没有任何关于视图的概念,也不知道在接收命令或更改绑定属性时视图的状态。似乎我需要一些服务来跟踪用户执行可撤销操作时哪个视图处于活动状态,并获取其状态以供稍后恢复。
在MVVM中实现撤销/重做的最佳实践是否有共识?我对Daniel Vaughan在他的Calcium项目中如何实现感到感兴趣;据说Blend是使用MVVM模式编写的,它的行为就像我想要的应用程序,如果微软能解释一下他们是如何做到的那就太好了!

这个回答解决了你的问题吗?WPF M-V-VM中的撤销,它如何适配? - StayOnTarget
2个回答

2
你需要做的第一件事是确保将操作与界面完全分离。这意味着将影响数据的所有操作转换为离散的操作。这也意味着任何导致视图更改的内容都应记录为单独的操作。基本上,界面状态只应反映数据更改和基于命令的视图更改(有关视图更改的最后一个注释请参见下文)。
我们以前使用过的最成功的撤销系统允许嵌套IUndoableCommand对象。这些复合命令会卷起成一个单一的用户操作(您期望在“撤消”菜单中看到的类型的操作)。
我注意到你提到了在多窗体应用程序中使用撤消...这似乎是不寻常的行为。通常,撤消仅适用于单个控件内以及任何拖放操作。例外通常是基于图形的界面(而不是基于表单的界面)。在撤消期间更改表单相当于MS Word切换到另一个文档并继续撤消...对最终用户来说非常令人不安。可能需要让用户体验团队重新考虑设计的这个方面。只是我的两分钱。
希望这可以帮助你。

我现在也会根据你的提醒调查Calcium项目。谢谢。 - iCollect.it Ltd
感谢您的回答,HiTech。当您说“撤消仅限于单个控件”时,您是否意味着例如在具有几个文本框的表单(视图)上,用户必须将焦点放在更改源自的文本框上,以便通过该文本框撤消/重做所做的任何更改?将操作与界面完全分离 - 这是否意味着禁止视图中的控件与视图模型上的属性之间的双向绑定?不幸的是,我们的应用程序既有交互式绘图表面(画布),也有类似Blend / VS的表单;它很复杂。非常感谢您的想法! - JamesCo

1

@JamesCo,

我已经为 WPF 应用程序实现了撤销/重做功能,并将我的撤销/重做代码发布到 http://muf.codeplex.com/。您也可以通过 NuGet 获取它。只需搜索“MUF”或“Monitored Undo Framework”。它支持 Silverlight 4.0、.NET 3.5、4.0 和 WP7。

我的 WPF 应用程序还使用了 MVVM,在某些情况下,允许撤消选择更改等操作。我还跟踪了在 WPF Frame 中显示的活动“页面”,以便将用户移回撤消操作所应用的页面。

该库采用了灵活的方法来编写每个步骤的撤销/重做操作。最终,它只需要一个撤销委托和一个重做委托。你可以让这些代表做任何你想要的事情。库中包括一个默认实现,它只需要对象、属性的名称、旧值和新值。它构建基于反射的委托,根据需要应用旧值或新值。

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

最后,该库包括批处理更改的支持。在多个操作应作为一个单元一起撤消时,这非常有用。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接