【问题标题】:MVVM Inheritance With View Models视图模型的 MVVM 继承
【发布时间】:2009-06-10 19:25:47
【问题描述】:

我想知道如何在 MVVM 模式中使用视图模型处理继承。在我的应用程序中,我有一个类似于以下内容的数据模型:

class CustomObject
{
    public string Title { get; set; }
}

class CustomItem : CustomObject
{
    public string Description { get; set; }
}

class CustomProduct : CustomItem
{
    public double Price { get; set; }
}

在我的应用程序中,我有一个 ViewModelBase 类,然后将有以下视图模型:

  • CustomObjectViewModel
  • CustomItemViewModel
  • CustomProductViewModel

CustomObjectViewModel 的粗略实现类似于以下内容:

class CustomObjectViewModel : ViewModelBase
{
    private readonly CustomObject _customObject;

    public CustomObjectViewModel( CustomObject customObject )
    {
        _customObject = customObject;
    }

    public string Title
    {
        // implementation excluded for brevity
    }
}

在我看来,我的视图模型会以与我的模型相同的方式扩展自己(CustomItemViewModel 扩展 CustomObjectViewModel 等等),这似乎是合乎逻辑的。但是,我注意到当我沿着继承树向下走时,我将添加对同一对象的其他引用。这对我来说似乎有点过分了,我想知道如何解决这个问题,以及是否有可能让它变得更干净。

【问题讨论】:

    标签: c# wpf design-patterns mvvm


    【解决方案1】:

    通常我会建议您不要在不同的 ViewModel 类之间进行继承,而是让它们直接从一个公共抽象基类继承。
    这是为了避免引入不必要的复杂性 污染 ViewModel 类的接口,成员来自层次结构中的更高层,但不完全内聚类的主要目的。
    继承带来的耦合将也可能使更改 ViewModel 类而不影响其任何派生类变得困难。

    如果您的 ViewModel 类总是引用单个 Model 对象,您可以使用泛型将此规则封装到基类中:

    public abstract class ViewModelBase<TModel>
    {
        private readonly TModel _dataObject;
    
        public CustomObjectViewModel(TModel dataObject)
        {
            _dataObject = dataObject;
        }
    
        protected TModel DataObject { get; }
    }
    
    public class CustomObjectViewModel : ViewModelBase<CustomObject>
    {
        public string Title
        {
            // implementation excluded for brevity
        }
    }
    
    public class CustomItemViewModel : ViewModelBase<CustomItem>
    {
        public string Title
        {
            // implementation excluded for brevity
        }
    
        public string Description
        {
            // implementation excluded for brevity
        }
    }
    

    【讨论】:

    • 我已经使用了此处所示的泛型模式,我不得不说,对于 ViewModel 的继承层次结构,我并没有遇到任何问题。
    • 在许多情况下它肯定会毫无问题地工作。但是在我看来,我认为 ViewModel 类与 Views 紧密耦合。如果 ViewModel 类之间的关联共享一些通用 UI,那么它们之间的继承将是有意义的。
    • 我正面临理查德经历的相同场景,除了我的问题是关于视图的。我有一个包含 10 个字段的抽象类,它的各种子类添加了更多字段(每个都添加了它自己的),我应该如何创建各种视图?我不想在每个字段中重新声明基本字段(我仍然不太确定 ViewModel 本身,也希望能提供任何帮助)。
    • @Shimmy 如果您有一段 UI 想要在多个视图中重用,您可以将其创建为 UserControl 并通过依赖属性公开其数据和命令。这样,您可以将 ViewModel 关联到承载 UserControl 的 View 绑定到该属性以控制其行为。
    • 已经好几年了,但我觉得这段代码有点混乱。为什么抽象基类中的继承类之一的构造函数?这是如何工作的?
    【解决方案2】:

    与上面Enrico的评论有关。 ViewModels 不应该与视图紧密耦合,它应该是相反的。视图应该与 ViewModel 松散耦合。 ViewModel 不应该知道视图,这使您可以轻松地对 ViewModel 进行单元测试。View 与 ViewModel 之间的所有交互都应通过 ViewModel 中的属性(用于操作的 ICommand 属性和用于数据绑定的其他属性)来实现。

    正确的一件事是 ViewModel 与 Model 紧密耦合,因此上面使用泛型允许很多可扩展性。这是我推荐的模式。

    通过提供一个基本上只公开属性的 ViewModel 类,它应该允许您将其放入任何类型的表示框架并利用您之前使用的所有代码。换句话说,如果实施得当,您可以将 ViewModels 程序集放入 ASP.NET MVC 应用程序中,并将视图与属性绑定,并且无需更改代码。

    一篇关于 MVVM 基础的好文章是:this one. 我真的认为 MVVM 是 UI 开发的最佳选择。显然我们不能都使用它,因为它需要使用 MVVM 方法从头开始构建应用程序,但是当您构建一个新应用程序时,这不是问题。

    我对 ICommand 的一个抱怨是它位于基本上用于 WPF 的 PresentationCore 程序集中。如果 Microsoft 想要松散耦合,它应该完全在另一个程序集中。

    【讨论】:

    • 让我澄清一下我的观点:“耦合”并不是说 ViewModel 类应该对 View 有任何依赖。但是,它应该公开与正在使用的特定视图显示的内容相关的数据/行为
    • 关于你的抱怨:这在 .NET4.5 中发生了变化:它现在是 System.dll msdn.microsoft.com/en-us/library/…的一部分
    【解决方案3】:

    我很想看看是否有更好的答案,但是当我遇到同样的问题时,我总是将对象的显式强制转换为私有属性,如下所示:

    class CustomObjectViewModel : ViewModelBase
    {
        protected readonly CustomObject CustomObject;
    
        public CustomObjectViewModel( CustomObject customObject )
        {
            CustomObject = customObject;
        }
    
        public string Title
        {
            // implementation excluded for brevity
        }
    }
    
    class CustomItemViewModel : CustomObjectViewModel 
    {
        protected CustomItem CustomItem  { get { return (CustomItem)CustomObject; } }
    
        public CustomItemViewModel( CustomItem customItem )
            :base(customItem)
        {
        }
    }
    

    它有效,是我想出的最好的,但对我来说从来没有觉得很干净。

    【讨论】:

    • 我认为这实际上是个好主意...这样您就不会在继承的 ViewModel 中复制模型对象
    【解决方案4】:

    我认为这里的问题是每个 View 应该有一个 ViewModel,而不是每个模型都有一个 ViewModel。

    原因很明显,因为您只能将一个对象设置为 DataContext,该对象应该是该 View 的 ViewModel。

    【讨论】:

      猜你喜欢
      • 2011-09-27
      • 2019-01-27
      • 2014-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-07
      相关资源
      最近更新 更多