MVVM架构:一个模型 - 几个视图模型+数据访问的位置

时间:2016-02-14 13:26:56

标签: c# entity-framework mvvm architecture

我对我的MVVM应用程序(以前称为WinRT,现在面向UWP)的数据访问架构感到困惑。我不太确定如何在UI中传播更改以及在何处访问数据层。

这是基本架构:

  1. 模型图层:包含仅具有自动属性的模型(没有引用其他模型的导航属性,只有ID;因此它们基本上只是数据库的表示)。它们没有实现INotifyPropertyChanged。
  2. 数据访问层:使用sqlite-net在数据库中存储模型的存储库。它公开了基本的CRUD操作。它返回并接受模型层中的模型。
  3. 的ViewModels
    • 模型的ViewModel :它们包围模型并公开属性。有时我将控件(例如TextBoxes)的内容双向绑定到属性。然后,setter访问数据层以保持此更改。
    • PageViewModels for Views :它们包含来自上方的ViewModel和命令。许多命令变得很长,因为它们进行数据访问,执行特定于域的逻辑并更新PageViewModels属性。
  4. 视图(页面):它们绑定到PageViewModels并通过DataTemplate绑定到模型的ViewModel。有时会有双向数据绑定,有时候我会使用命令。
  5. 我现在有这个架构的几个问题:

    问题1:一个模型可以在几个宫殿的屏幕上显示出来。例如,主 - 详细视图,显示类型的所有可用实体的列表。用户可以选择其中一个,其内容显示在详细视图中。如果用户现在在详细视图中更改属性(例如模型的名称),则应立即在主列表中反映更改。这样做的最佳方式是什么?

    1. 为模型设置一个ViewModel?我认为这没有多大意义,因为主列表只需要非常少的逻辑,而详细信息视图则更多。
    2. 模型实现INotifyPropertyChanged ,从而将更改传播到ViewModels?我遇到的问题是,数据层当前不保证它在一个模型id上为两次读操作返回的对象是相同的 - 它们只包含从数据库读取的数据,并在读取时新创建(我认为这是sqlite-net的工作方式)。由于ViewModel中的所有PropertyChanged事件订阅,我也不确定如何避免发生内存泄漏。我应该实现IDisposable并让PageViewModel调用其子项的Dispose()方法吗?
    3. 我目前在数据访问层上有 DataChanged事件。只要发生创建,更新或删除操作,就会调用它。可以同时显示的每个ViewModel都会侦听此事件,检查更改的模型是否为ViewModel的模型,然后更新其自己的属性。我再次遇到内存泄漏的问题,这变得很慢,因为太多的ViewModel必须检查更改是否真的适合他们。
    4. 另一种方式?
    5. 问题2:我也不确定我访问数据的地方是否真的很好。 PageViewModels变得非常复杂,基本上做了一切。并且所有ViewModel都需要使用我的架构了解数据层。

      我一直在考虑使用sqlite-net和使用Entity Framework 7来废弃数据访问。这会解决上面的问题,即当我使用时,它是否保证了一个模型的对象标识相同的背景?我还认为它会简化ViewModel,因为我很少需要读取操作,因为这是通过导航属性完成的。

      我一直想知道在MVVM应用程序中是否有两路数据绑定是好主意,因为它需要属性设置器调用数据访问层来保持更改。最好只进行单向绑定并通过命令保留所有更改吗?

      如果有人可以对我的架构进行评论并提出改进建议或指向关注我的问题的MVVM架构的好文章,我会非常高兴。

1 个答案:

答案 0 :(得分:3)

  
      
  1. 为模型设置一个ViewModel?我认为这没有多大意义,因为主列表只需要非常少的逻辑,而且详细信息视图更多。
  2.   

ViewModel不依赖于模型。 ViewModel使用该模型来满足视图的需求。 ViewModel是视图的单一联系点,因此viewmodel必须提供视图需求。所以它可以是单个模型/多个模型。但是您可以将单个ViewModel分解为多个子ViewModel,以使逻辑更容易。它的详细信息窗格可以分为具有自己的视图模型的用户控件。您的母版页将只有一个将托管此控件的窗口,而MasterViewmodel会将职责推送到子ViewModel。

  
      
  1. 让模型实现INotifyPropertyChanged,从而将更改传播到ViewModels?我对此有的问题是   数据层目前不保证它返回的对象   对于一个型号id上的两个读取操作是相同的 - 它们只是   包含从数据库读取的数据,并在以后新创建   他们被阅读(我认为这是sqlite-net的工作方式)。我也没有   确实如何避免因为所有问题而发生内存泄漏   来自ViewModels的PropertyChanged事件订阅。我是不是该   实现IDisposable并让PageViewModel调用它的子节点   Dispose()方法?
  2.   

危险不是使用INotifyPropertyChanged,而是正确地说了它的描述和取消订阅。无论何时需要订阅任何活动 - 不仅INotifyPropertyChanged您需要使用IDisposable取消订阅自己及其子ViewModels。我不清楚您描述的数据层,但如果它发布属性更改事件进行任何修改我没有看到使用INotifyPropertyChanged的任何问题。

  

3.我目前在我的数据访问层上有一个DataChanged事件。只要发生创建,更新或删除操作,就会调用它。每   可以同时显示的ViewModel侦听此事件,   检查更改的模型是否是ViewModel for和   然后更新自己的属性。我又有了问题   内存泄漏,这变得很慢,因为太多的ViewModel必须这样做   检查改变是否真的适合他们。

如前所述,如果您正确处理所有模型的订阅/取消订阅,则无需担心INotifyPropertyChanged的性能问题。但是,可能会增加问题的是您为数据库请求数据的调用次数。您是否考虑过使用Async ...等待数据访问层,该层不会阻止任何更新发生的UI。即使数据更新很慢,也不会被数据调用阻止的反应式UI是更好的选择。

因此,尝试添加通过DAL层抽象的数据访问服务,并提供访问数据的异步方法。另请查看Mediator Pattern。这可能会有所帮助。

  

我也不确定我访问数据的地方是否真的很好   选择。 PageViewModels变得非常复杂   基本上做的一切。并且所有ViewModel都需要知识   我的架构的数据层。

我看到的两个主要问题,

  1. 如果您觉得PageViewModel太大,可以分解为可管理大小的子视图模型。它非常主观,所以你必须尝试使用​​自己的viewmodel来查看所有部分可以分解为自己的组件/ usercontrol。
  2. 当您说 ViewModels需要数据层知识时,我希望您的意思是他们依赖于管理DAL层服务的接口,并且不能使用CRUD方法直接访问类。如果没有尝试添加您在视图模型中实际执行的抽象层。这将处理DAL CRUD操作。
  3.   

    我一直在考虑使用sqlite-net和使用来废弃数据访问   相反,实体框架7。

    在没有确凿证据的情况下,不要尝试用EF替换sqlite-net。在尝试进行如此大的更改之前,您需要在应用中衡量性能。如果问题出在您的代码而不是您正在使用的组件中,该怎么办?首先尝试解决上述问题,然后通过接口隔离DAL层,并在需要时替换它。

      

    我也一直想知道是否有两路数据绑定是好的   完全在MVVM应用程序中的想法,因为它需要属性设置器   调用数据访问层以保留更改。是不是更好   只执行单向绑定并通过命令保留所有更改?

    如果您每次更改字段/每次按键时都直接调用数据库,那么就会出现问题。然后,您应该拥有数据模型的副本,并仅在单击保存按钮时保留更改。