首页 文章

在MVVM中,每个ViewModel是否只耦合到一个Model?

提问于
浏览
33

在MVVM实现中,每个 ViewModel 只耦合到一个 Model

我试图在项目中实现MVVM模式,但我发现有时, View 可能需要来自多个 Models 的信息 .

例如,对于 UserProfileView ,其 UserProfileViewModel 可能需要来自 UserAccountModelUserProfileSettingsModelUserPostsDataModel 等的信息 .

但是,在我读到的关于MVVM的大多数文章中,ViewModel仅通过依赖注入包含一个模型 . 因此构造函数只接受一个Model .

ViewModel 必须从多个 Models 获取信息时,它将如何工作?或者这种情况会发生在MVVM中吗?

PS:我没有使用Prism或Unity Framework . 我正在尝试将类似的模式实现到我正在使用的不使用Prism或Unity的项目中 . 这就是为什么我需要准确理解其中一些是如何工作的 .

7 回答

  • 2

    在我对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
      }
    }
    
  • 2

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

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

  • 1

    viewmodel包含“视图逻辑” - 所以你想在视图上显示的所有内容都是通过viewmodel公开的 . 如果你想显示来自不同“模型”的数据,那么你的viewmodel会聚合这个并且视图可以绑定到 .

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

    编辑:为什么你认为:

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

    EDIT2:

    有两种主要的方法可以使用mvvm,首先是“View First”,第二种是“Viewmodel First”,你当然可以将它们混合起来并根据需要选择最佳方法 .

  • 39

    ViewModel可能并且在许多情况下确实使用多个模型 . 它本身就是您视图的“模型” .

    考虑用户输入其个人信息(包括地址)的 Profiles 屏幕 . 如果地址存储在“地址”表中,其余地址存储在“配置文件”表中,则ViewModel使用配置文件和地址模型创建统一的ViewModel .

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

  • 4

    我会确保你理解view,viewmodel和所有其他模型类之间的区别 . ViewModel是模型对象,其中填充了视图可以绑定到的数据 . 它只是为了向视图提供数据而存在,这使得ViewModel对象可以单元测试,并且整个业务逻辑与视图分离 . 因此,您可以完全开发业务逻辑而无需使用视图本身,并且可以仅使用构建或使用其他视图并绑定到ViewModel对象的属性来替换视图 . 例如,如果视图中包含空文本字段,则文本字段的内容可以绑定到视图模型的不同属性 .

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

    ViewModel可以从许多不同的源,业务对象,数据库等中获取它返回到视图的数据 .

  • -2

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

    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 . 因此,View可以从 ViewModel1.ViewModelA.TestValue 获取数据 .

  • 14

    只需在视图中使用用户模型即可

    public partial class User : Login
    {
        public string Password { get; set; }
    
        public List<Customer> customer { get; set; }
    }
    

    在此继承的另一个模型登录和此模型中也使用的客户模型..

相关问题