【问题标题】:Where to convert entities/models to viewmodels in MVVM?在 MVVM 中将实体/模型转换为视图模型的位置在哪里?
【发布时间】:2015-09-06 10:37:04
【问题描述】:

在 MVC 中它非常简单:

客户端发出请求,控制器要求业务逻辑做一些花哨的事情,业务逻辑要求存储库返回一些数据,然后存储库返回数据,业务逻辑负责将数据从实体转换为视图模型,然后返回给客户端.

在 MVVM 中我几乎迷路了,因为视图模型本身负责向业务逻辑发出请求,所以没有像控制器这样的“中间层”。我可以在商业逻辑项目中实现映射器,但由于视图模型负责向商业逻辑询问数据,它会创建循环引用。

那么我必须在哪里让这种“魔法”发生呢?

【问题讨论】:

  • 您的业务实体来自哪里。远程服务器?请求它们时,在您的回调中将它们包装在您希望 UI 处理的任何 UI 模型中。
  • 它是对 DB 的简单请求。我想要的是让我的 BL 返回 ViewModel,而不是实体

标签: c# mvvm mvvm-light


【解决方案1】:

我将尝试通过一个简单的示例来提供一些背景信息。

请注意,下面的所有代码都只是概念性的,写在这里而不是在 VS 中。

将您的 ViewModel 视为模型的包装器。 您的模型由属性公开,因此您可以绑定到它或从视图中绑定到它的属性。

你的视图模型:

  public class SomeEntityViewModel : NotificationObject
  {
       private SomeEntity _someEntity;
       public  SomeEntity SomeEntity
       {
           get{ return _someEntity;}
           set
           {
               _someEntity = value;
               RaisePropertyChanged("SomeEntity");
           }  
       }  
  } 

现在假设您向服务器发送请求并等待响应。

我们还假设您有一个更高的对象(如父 ViewModel)来启动您的 VM:

  public class SomeEntityContainerViewModel : NotificationObject
  {
      public ObservableCollection<SomeEntityViewModel> Items;

      public void async OnRequestNewEntity() 
      {
         SomeEntity newEntity = await _someEntityService.CreateSomeEntityAsync();
         var vm = new SomeEntityViewModel{ SomeEntity = newEntity};
         Items.add(vm);
      }
  }

您的 SomeEntityContainerView 其中 SomeEntityContainerViewModel 是 DataContext :

  <UserControl>
      <Button Command="{Binding RequestNewEntityCommand}" />
      <ItemsControl ItemsSource="{Binding Items}" />
  </UserControl>

您的 SomeEntityView 其中 SomeEntityViewModel 是 DataContext :

    <UserControl>
        <TextBlock Text="{Binding SomeEntity.Name}" />
    </UserControl>

最简单的设计:

您的模型需要“哑”,只有数据。 您的 ViewModel 是最接近 Controller 的等价物,它将处理逻辑,它是将您的模型包装(不转换)到视图模型中的组件。

在上面的示例中,我们有一些更高的对象,一个父 ViewModel,它启动我们的 ViewModel。

这相当于一个控制器的作用域,它在 DOM 中具有其他嵌套的控制器。

【讨论】:

  • 很好的答案,我赞赏您尝试回答这个问题 - 由于定义冲突,这不是一个简单的话题。但是,我会明确指出 VM(在 MVVM 中)不等同于控制器。您可以这样编码,但随后您开始混迹 MVVM 模式——VM 应该简单地包含和塑造实体数据,它不应该包含业务逻辑(属于“模型” , IMVHO 在 MVVM 模式中定义不足)。
  • 我说它是视图模型的“最接近的等价物”。至于 BL,这取决于您对 BL 的定义,调用服务然后更新您的虚拟机中的一些数据是否考虑了 bl 或者是收集数据的方式 bl ?
【解决方案2】:

基于 mvvm-light 参考,我在这里假设一个 WPF 应用程序。 我在第 1 段中提到您的业务逻辑(我将这里称为服务)负责转换为视图模型。我会说该服务不应该知道该视图。所以在这种情况下,控制器(或由控制器或模型绑定器调用的映射器)将处理映射。

在 MVVM 中(我在此尝试为您进行比较时的观点),ViewModel 的行为与控制器非常相似,因为它可以获取模型、映射并绑定到可观察对象。然后也是绑定到视图的模型(mvc中经常使用的视图模型)。

所以我认为这里的诀窍是移动应该发生映射的位置。服务不应该对视图有任何了解。它们没有与视图耦合,这是一件好事。

【讨论】:

  • 所以视图模型本身应该负责转换?
  • 在 Mvvm 中?是的,我相信。作为 javascript vm 中的示例,方法将从 Web API 获取数据并填充 vm。 VM 负责从服务中获取数据并自行填充。我将其用作例如,因为它更容易在客户端服务器设置中将其分开,但其原理与 WPF 中的 MVVM 相同。该服务负责提供模型。
【解决方案3】:

在 MVVM 中,您所指的“业务层”是“模型”——实际上,视图模型之后的任何内容都被视为“模型”的一部分。然而,在我做过的任何工作中,我总是将此模型拆分为 n 层,通常带有一个控制器样式类,该类使用服务从数据存储库中检索数据实体。

在哪里将实体/模型转换为视图模型?

严格来说,你不知道。视图模型可以包含实体(即VM具有它们的ObservableCollection),或者视图模型可以包装一个实体(在您可能需要显示选项的列表控件中很有用或按行执行操作)。

实体的 MVC 方法比 MVVM 更脏,你最终会得到一个更丰富的业务模型,而不是一个漂亮的精益实体。在 MVVM 中,“丰富性”主要由视图模型拆分和处理,并且您尝试使数据实体尽可能简单(是的,您可以在实体中包含验证等内容,但您应该只在必要时进行,其他验证应该在虚拟机或模型中的某个地方进行)。

【讨论】:

    【解决方案4】:

    你的问题是错误的。视图模型代表了用户与您的应用程序交互背后的逻辑,所以问题应该是“当用户交互请求时,视图模型如何获取实体和模型?”。答案是:“使用依赖注入框架,例如 Ninject”。这允许您将实体范围限定为 WPF 应用程序中的页面、MVC 或 WCF 应用程序中的 Web 请求、任何外部控制台实用程序中的单例或测试框架中的模拟对象……所有这些都无需您的视图模型知道或关心关于这些实体或提供它们的服务是如何在内部创建或工作的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-11
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 2014-11-27
      • 1970-01-01
      相关资源
      最近更新 更多