【问题标题】:Best practice for keeping Models and ViewModels in sync保持模型和视图模型同步的最佳实践
【发布时间】:2011-06-21 16:21:23
【问题描述】:

我正在开发一个大型 Silverlight 应用程序,该应用程序使用双工 Net.TCP 与 WCF 后端通信。我正在将此应用程序从 MVC 方法转移到 MVVM。但是,我正在努力寻找正确的方法来实现我的 ViewModel。我们正在为我们的模型使用 WCF 生成的代理,这非常复杂,涉及几十个类、大量集合和各种多对多关系。例如,一个用户可以属于许多房间,一个房间可以有很多用户,一个用户可以有很多共享文件,每个共享文件可以与用户当前所在的任何房间共享。那种东西。

最重要的是,因为我们在双工模式下使用 WCF,所以对模型的更改可以由最终用户触发,也可以由后端的 WCF 服务触发。换句话说,我们使用的模型比您在各种 MVVM 书籍/文章/博客文章中看到的典型“模型”复杂几个数量级。这就是问题所在,因为让我们的 ViewModel 层与底层 Model 层保持同步变得有点麻烦。

这是一个典型的问题。一个新的“用户”加入了一个“房间”,因此 WCF 服务向房间中的所有其他用户发出“SessionAdded”通知。 SessionAdded 通知带有一个 Session 对象,该对象具有一个链接的 Room 和一个链接的 User 对象。这个从 WCF 服务反序列化的 Room 对象与本地客户端上的 Room 对象基本相同,并且可能具有大部分相同的数据,但它肯定没有所有相同的数据,并且至少有一些数据(比如它的空 Whiteboards 集合)肯定是错误的。所以我们需要以某种方式获取这些传入数据并将其合并到我们现有的模型中。然后我们需要在每个新对象之上创建 ViewModel,和/或使用新对象和/或其数据更新现有 ViewModel。

现在我们通过让各种 ViewModel 响应相关的 WCF 通知事件来处理这个问题,并尽最大努力修复它们的底层模型和相关的视图模型。我们已经找到了一些技巧,比如 SynchronizedObservableCollection(有点像 here),它监视(比如说)Room.Sessions ObservableCollection 并自动创建相应的 SessionViewModels 并将它们放在 RoomViewModel.SessionViewModels 集合中。我们还使用了 ViewModelFactory,它缓存视图模型并确保包装给定 Session 的 SessionViewModel 保持不变,即使底层 Session 对象被更改。 (如果重要的话,我们使用的是视图模型优先的方法,因为我们需要创建新的 UI 元素以响应 WCF 通知触发的 ViewModel 的变化。)

所有这些都有效。基本上。大多数时候。你懂的。但是要维护的代码很多,而且很容易出错。只要您能记住应该发生的事情,单元测试就很方便,但是当您处理完第 20 个级联 CollectionChanged 事件时,很难跟踪所有这些如何组合在一起以及您首先要测试的内容.换句话说,它非常脆弱。

在我看来,这是很多人一定遇到过的那种情况,我很好奇其他人是如何面对它的。我可以想出几种可能让它变得更好的方法:

(1) 将客户端模型视为一种需要保持完全一致的数据库,并实现一个客户端数据访问层,其工作是保持模型一致。对模型的所有更新,无论是来自用户还是服务器,都需要通过这一层。它有点像实体框架,myRoom.Users.Add(myUser) 会自动设置myUser.Room = myRoom,反之亦然,依此类推。 (这尤其是似乎某个地方的某个人应该已经开发的部分,虽然我还没有找到它。)

(2) 依靠TrussObtics 之类的东西,以使所有部分保持同步。不太确定这将如何工作,但从理论上讲,这应该是可能的。

还有……还有什么?我很好奇用于解决此问题的模式或框架。

【问题讨论】:

    标签: silverlight wcf mvvm synchronization


    【解决方案1】:

    我理解您的痛苦 - 我目前正在使用 MVVM 模式开发一个复杂的数据可视化应用程序。要问自己一个非常重要的问题是,“视图模型是否在您使用它的任何地方都增加了价值?”换句话说,是否有地方只是将模型层上的属性转发到您的视图?

    我经常发现有一些代码区域,通常是在细节级别(例如,Person 对象的属性、年龄、姓名、名字),其中视图模型实际上根本没有添加任何值,而更多课程级别,它通过构建视图/窗口等来增加价值......

    我倾向于对 MVVM 采用自适应方法,在顶层(Windows、窗格、窗体)我总是有一个视图模型,但如果视图模型的某些部分非常简单以至于视图模型没有增加任何价值,我直接将它们暴露给视图。此外,在某些情况下,您需要将模型直接暴露给视图以获得更好的性能。

    最后,如果你发现需要重新引入视图模型来解决棘手的绑定问题,我写了一个简单的模式 mini-MVVM,它应用了本地视图模型:

    http://www.scottlogic.co.uk/blog/colin/2009/08/the-mini-viewmodel-pattern/

    希望对您有所帮助。

    【讨论】:

    • 这基本上就是我正在做的事情:我不是纯粹主义者:-)。我的每个 ViewModel 都有一个 Model 属性,该属性公开了底层模型。由于此实例中的模型始终是 WCF 生成的类,因此它实现了 INotifyPropertyChanged,因此它作为绑定源工作得相当好。我添加到 ViewModel 的唯一属性是以某种方式实际增加价值的属性。但是我仍然要处理当服务器向客户端发送带有更新模型的消息时需要刷新模型的问题。
    猜你喜欢
    • 1970-01-01
    • 2011-09-16
    • 2012-12-04
    • 2011-04-08
    • 2011-03-06
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多