此外,由于我们使用WCF在双工模式下运行,模型的更改可以由最终用户或后端的WCF服务触发。换句话说,我们使用的模型比任何MVVM书籍/文章/博客中展示的典型“模型”复杂得多。这就是问题所在,因为让我们的ViewModel层与底层Model层保持同步已成为一件有点麻烦的事情。
这是一个典型的问题。新用户加入房间后,WCF服务向房间中的所有其他用户发送“SessionAdded”通知。SessionAdded通知携带了一个Session对象,该对象具有链接的Room和链接的User对象。从WCF服务反序列化的Room对象基本上与本地客户端上的Room对象相同,并且可能具有大部分相同的数据,但它肯定不具有完全相同的数据,至少其中一些数据(如其空的Whiteboards集合)肯定是错误的。因此,我们需要以某种方式将这些传入的数据合并到我们现有的模型中。然后,我们需要在每个新对象上创建ViewModels,和/或使用新对象和/或其数据更新现有的ViewModels。
目前,我们通过让各种ViewModel响应相关的WCF通知事件并尽力修复它们的底层模型和相关视图模型来处理这个问题。我们已经想出了一些技巧,比如一个SynchronizedObservableCollection(类似于这里),它监视(例如)Room.Sessions ObservableCollection,并自动创建相应的SessionViewModels并将它们放置在RoomViewModel.SessionViewModels集合中。我们还使用了一个ViewModelFactory,它缓存视图模型并确保,例如,包装给定会话的SessionViewModel保持不变,即使基础会话对象被替换。(如果有关系的话,我们采用视图模型优先的方法,因为我们需要的大部分内容是根据我们的WCF通知触发的ViewModel更改而创建新的UI元素。)
所有这些都有效。基本上。大部分时间。你懂的。但是维护这么多代码很麻烦,而且容易出错。单元测试很方便,只要您记得应该发生什么,但是当您处理第20个级联CollectionChanged事件时,很难跟踪所有这些内容如何配合以及您最初为什么进行测试。换句话说,所有这些都相当脆弱。
我觉得这是许多人必须遇到的情况,我很好奇其他人是如何面对它的。我可以想到几种方法来使其更好:
(1) 将客户端模型视为一种需要完全保持一致的数据库,并实现一个客户端数据访问层,其职责是保持模型的一致性。所有对模型的更新,无论是来自用户还是服务器,都需要通过此层进行。这有点像实体框架,例如myRoom.Users.Add(myUser)
将自动设置myUser.Room = myRoom
,反之亦然,以此类推。(尤其是这一部分,似乎某个地方应该已经开发出来了,虽然我还没有找到。)
(2) 依赖于类似Truss或Obtics的东西,以保持所有组件的同步。还不太确定它的工作原理,但从理论上讲,似乎是可行的。
还有什么?我很想知道用于解决此问题的模式或框架。