2011-02-04 125 views
5

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

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

这是一个典型的问题。新的“用户”加入“房间”,因此WCF服务会向房间中的所有其他用户发出“加入会话”通知。 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的更改创建新的UI元素。)

所有这些工作。基本上。大多数时候。你懂。但是需要维护很多代码,而且很容易出错。单元测试很方便,只要你能记住应该发生的事情,但在你完成处理你的第20个级联的CollectionChanged事件的时候,很难跟踪所有这些如何结合在一起以及你在第一个地方测试了什么。换句话说,这一切都很脆弱。

在我看来,这是很多人必须遇到的情景,我很好奇其他人如何面对它。我可以想到一些方法或许可以使它变得更好:

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

(2)依靠诸如TrussObtics之类的东西来保持所有片段的同步。不太清楚这种方式会如何工作,但理论上这听起来应该是可能的。

还有什么?我很好奇已经用于解决这个问题的模式或框架。

回答

3

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

我经常发现代码的区域通常在细节层面(例如Person对象,Age,Name,Forename的属性),其中视图模型根本没有实际添加任何值,而在更多的课程级别,它通过构建视图/窗口等来增加价值...我一直有一个视图模型,但如果我总是有一个视图模型部分视图模型非常简单,视图模型不会添加任何值,我直接将它们暴露给视图。此外,在某些情况下,您需要直接将模型展示给视图以获得更好的性能。

最后,如果你发现你需要再推出一个视图模型来解决一个棘手的结合问题,我写了一个简单的模式,迷你MVVM,它适用于局部视图模型:

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

希望有帮助。

+0

这就是我在做的事情:我不是纯粹主义者:-)。我的每个ViewModel都有一个Model属性,它公开了基础模型。由于这个实例中的模型总是一个WCF生成的类,它实现了INotifyPropertyChanged,所以它作为一个绑定源很合适。我添加到ViewModel的唯一属性是以某种方式实际增加值的属性。但是当服务器用更新后的模型向客户端发送消息时,我仍然需要处理模型需要刷新的问题。 – 2011-02-05 08:32:18