视图模型的MVVM继承

Ric*_*ire 18 c# wpf design-patterns mvvm

我想知道如何在MVVM模式中使用View Models进行继承.在我的应用程序中,我有一个类似于以下内容的数据模型:

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

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

class CustomProduct : CustomItem
{
    public double Price { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在我的应用程序中,我有一个ViewModelBase类,然后将有以下View Models:

  • CustomObjectViewModel
  • CustomItemViewModel
  • CustomProductViewModel

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

class CustomObjectViewModel : ViewModelBase
{
    private readonly CustomObject _customObject;

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

    public string Title
    {
        // implementation excluded for brevity
    }
}
Run Code Online (Sandbox Code Playgroud)

对我来说似乎合乎逻辑的是,我的视图模型将以与我的模型相同的方式扩展自己(CustomItemViewModel扩展CustomObjectViewModel等等).但是,我注意到,当我继承继承树时,我将添加对同一对象的其他引用.这对我来说似乎相当过分,并且想知道如何处理这个问题以及是否有可能使它更清洁.

Enr*_*lio 19

通常,我建议您不要在不同的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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在许多情况下,它肯定会没有问题.但是在我看来,我认为ViewModel类与Views紧密结合.如果ViewModel类的关联视图共享一些公共UI,则它们之间的继承是有意义的. (3认同)
  • @Shimmy 如果您有一个要在多个视图中重用的 UI,您可以将其创建为 [UserControl](http://msdn.microsoft.com/en-us/library/ms617852.aspx) 并公开其数据和命令通过依赖属性。这样,您就可以将 ViewModel 关联到托管 UserControl 的 View 绑定到该属性以控制其行为。 (3认同)
  • 已经好几年了,但我发现这段代码有点令人困惑.为什么抽象基类中的一个继承类的构造函数?这是如何运作的? (2认同)

Mar*_*ris 5

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

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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

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


Jos*_*ose 5

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

有一点是真实的,ViewModel与模型紧密耦合,因此上面使用泛型可以实现很多可扩展性.这是我推荐的模式.

通过提供基本上只暴露属性的ViewModel类,它应该允许您将其插入任何类型的表示框架并利用您之前使用的所有代码.换句话说,如果正确实现,您可以将ViewModel程序集放入ASP.NET MVC应用程序中,并将视图绑定到属性,并且不会更改代码.

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

我与ICommand的一个抱怨是它在PresentationCore Assembly中基本上用于WPF.如果微软想要松耦合,它应该完全在另一个组件中.

  • 让我澄清一下我的观点:使用"耦合"我并不是说ViewModel类应该对View有任何依赖性.但是,它应该公开与正在使用的特定View所显示的内容相关的数据/行为 (2认同)