39

在 MVVM 实现中,每个都只ViewModel耦合一个Model吗?

我正在尝试在项目中实现 MVVM 模式,但我发现有时,aView可能需要来自多个Models.

例如,对于 a UserProfileView,它UserProfileViewModel可能需要来自UserAccountModelUserProfileSettingsModelUserPostsDataModel等的信息。

然而,在我阅读的大多数关于 MVVM 的文章中,ViewModel 仅包含一个通过依赖注入的模型。所以构造函数只接受一个模型。

ViewModel它必须从多个Models. 或者这种情况会在 MVVM 中发生吗?

PS:我没有使用 Prism 或 Unity 框架。我正在尝试将类似的模式实施到我正在从事的不使用 Prism 或 Unity 的项目中。这就是为什么我需要确切地了解其中一些事情是如何工作的。

4

7 回答 7

47

在我对 MVVM 模式的理解中,唯一实际的要求是 View 从 ViewModel 的属性中获取所有数据(可能通过绑定机制)。ViewModel 是您专门为该视图制作的一个类,它负责根据需要自行填充。你可以把它想象成视图的 ActiveRecord。

因此,无论您在 ViewModel 中做什么来获取其属性应显示的数据,都无关紧要。您可以通过查询一些服务、读取一个或多个业务实体模型、在现场生成它或以上所有方式来获取它。需要结合所有这些东西来制作功能视图是完全正常的。

与任何演示模式一样,关键是将在屏幕上显示某些数据的过程与获取该数据的过程分开。这样您就可以分别测试流程的每个部分。

编辑:这是一个小但希望完整的依赖流示例。

// Model/service layer

public class MyModelA
{
  public string GetSomeData()
  {
    return "Some Data";
  }
}

public class MyModelB
{
  public string GetOtherData()
  {
    return "Other Data";
  }
}

// Presentation layer

public class MyViewModel
{
  readonly MyModelA modelA;
  readonly MyModelB modelB;

  public MyViewModel(MyModelA modelA, MyModelB modelB)
  {
    this.modelA = modelA;
    this.modelB = modelB;
  }

  public string TextBox1Value { get; set; } 

  public string TextBox2Value { get; set; }

  public void Load()
  {
    // These need not necessarily be populated this way. 
    // You could load an entity and have your properties read data directly from it.
    this.TextBox1Value = modelA.GetSomeData();
    this.TextBox2Value = modelB.GetOtherData();
    // raise INotifyPropertyChanged events here
  }
}

public class MyView
{
  readonly MyViewModel vm;

  public MyView(MyViewModel vm)
  {
    this.vm = vm;
    // bind to vm here
  }
}

// Application layer

public class Program
{
  public void Run()
  {
    var mA = new MyModelA();
    var mB = new MyModelB();
    var vm = new MyViewModel(mA, mB);
    var view = new MyView(vm);
    vm.Load();
    // show view here
  }
}
于 2012-10-26T11:18:43.270 回答
14

您可以在一个视图模型中使用多个模型。视图模型的目的是抽象出业务/数据层(即模型)。

但是,使用多个模型通常表明视图太大。您可能希望将其拆分为用户控件(具有自己的视图模型)。

于 2012-10-26T11:07:51.790 回答
4

视图模型包含“视图逻辑”-因此您想在视图上显示的所有内容都通过视图模型公开。如果您想显示来自不同“模型”的数据,那么您的视图模型会将其聚合起来,并且视图可以绑定到。

mvvm 的主要目的是 btw 单元测试。这意味着无需 UI 即可轻松测试视图逻辑。

编辑:你为什么认为:

ViewModel 在其构造函数中只有一个 View 参数

编辑2:

顺便说一句,使用 mvvm 有两种主要方法,第一种是“View First”,第二个是“Viewmodel First”,您当然可以将两者混合并选择最适合您需要的方法。

于 2012-10-26T11:31:55.447 回答
2

一个 ViewModel 可能并且在许多情况下确实使用多个模型。它本身就是您观点的“模型”。

考虑用户输入包括地址在内的个人信息的个人资料屏幕。如果地址存储在“addresses”表中,其余存储在“profile”表中,则 ViewModel 使用 Profile 和 Address 模型来创建统一的 ViewModel。

正如jgauffin在他的回答中提到的那样,很多时候您可以使用用户控件来实现一对一的关系,但您也可以通过尝试 100% 的时间来引入不必要的复杂性。

于 2012-10-26T11:12:16.317 回答
2

我会确保您了解视图、视图模型和所有其他模型类之间的区别。ViewModel 是填充了视图可以绑定到的数据的模型对象。它的存在只是为了向视图提供数据,这使得 ViewModel 对象可进行单元测试,并且整个业务逻辑与视图分离。因此,您可以在不使用视图本身的情况下完全开发业务逻辑,并且可以通过构建或使用另一个视图并绑定到 ViewModel 对象的属性来替换视图。例如,如果一个视图充满了空文本字段,则文本字段的内容可以绑定到视图模型的不同属性。

通常真的应该只有一个视图模型。但如果它太复杂,您可以使用绑定对象的子属性,如绑定到 ViewModel.SubClass.Property(子属性)中所述

ViewModel 可以从许多不同的来源、业务对象、数据库等获取它返回给视图的数据。

于 2012-10-26T11:13:15.827 回答
1

通常每个模型有一个 ViewModel。这些 ViewModel 包含处理模型数据的逻辑。另一方面,每个视图也都有自己的视图模型。所以这意味着:

class ModelA 
{
    bool TestValue{get;set;}
}
class ViewModelA<ModelA>
{
    ValueViewModel<bool> TestValue{get; private set;}

    public ViewModelA(ModelA model) 
    {
        base.Model = model;
        this.Initialize();
    }
}

class ModelB 
{
    string Username;
}
class ViewModelB<ModelB>
{
    ValueViewModel<string> Username{get; private set;}

    public ViewModelB(ModelB model) 
    {
        base.Model = model;
        this.Initialize();
    }
}

这些是封装模型的 ViewModel。视图有自己的 ViewModel:

public ViewModelForExactlyOneView
{
    public ViewModelA{get;set;}
    public ViewModelB{get;set;}
}

为了回答您的问题,ViewModel1 指的是 ViewModelA 和 ViewModelB。因此,视图可以从ViewModel1.ViewModelA.TestValue.

于 2012-10-26T11:05:21.823 回答
-4

只需在您的视图中使用用户模型

public partial class User : Login
{
    public string Password { get; set; }

    public List<Customer> customer { get; set; }
}

在此模型中继承了另一个模型登录,并且此模型中也使用了客户模型。

于 2015-06-17T09:35:06.107 回答