视图模型继承和重复的模型引用(viewmodel inheritance and duplicate

2019-09-17 10:41发布

我的问题是:如何管理的ViewModels的继承链?

我的情况:

我有一个标准ViewModelBase只实现了INotifyPropertyChanged接口。

而且我有都有一个GUID,它具有人的核心数据,与客户相关的东西一CustomerViewModel与员工相关的东西一EmployeeViewModel一个PersonBaseViewModel一个BusinessObjectViewModel。

所有的ViewModels肯定封装一个modelobject(客户,员工,PersonBase)。

  • BusinessObjectViewModel从ViewModelBase继承
  • PersonBaseViewModel从BusinessObjectViewModel继承
  • CustomerViewModel从PersonBaseViewModel继承
  • EmployeeViewModel从PersonBaseViewModel继承

该机型标配通过构造成视图模型。

如果我使用一个构造函数链(每视图模型使得在底座构造函数的调用)每个视图模型都有它的模型,从模型返回封装的值。

不过,我得在每一个视图模型模型属性。 在CustomerViewModel I的情况下将具有在CustomerViewModel,一个在PersonBaseViewModel和一个在BusinessObjectViewModel用于一个和基准相同的对象。 这听起来很愚蠢,我。

或者,我必须投在上面的ViewModels每个属性的访问。

ps的,这只是一小截出我的模型层次。

提前致谢。

Answer 1:

如果BusinessObject的和Person类(和它们的VM对应)是抽象的,那么你可以像这样访问权型号:

public abstract class BusinessObjectViewModel : ViewModelBase
{
    protected abstract BusinessObject BusinessObject { get; }

    protected BusinessObject Model { get { return this.BusinessObject; } }
}

public abstract class PersonViewModel : BusinessObjectViewModel
{
    protected abstract Person Person { get; }

    protected new Person Model { get { return this.Person; } }

    protected override sealed BusinessObject BusinessObject
    {
        get { return this.Model; }
    }
}

public class CustomerViewModel : PersonViewModel
{
    protected new Customer Model { get; set; }

    protected override sealed Person Person
    {
        get { return this.Model; }
    }
}

public class EmployeeViewModel : PersonViewModel
{
    protected new Employee Model { get; set; }

    protected override sealed Person Person
    {
        get { return this.Model; }
    }
}

这样每派生VM类提供通过实现抽象属性为其碱VM Model属性的值,并且隐藏了基类模型属性,所以每一个VM可与适当的类型的模型属性(因此没有铸造是必需的)。

这种方法有其优点和缺点:

优点:

  • 无铸造参与。

缺点:

  • 工作仅当基类(BusinessObjectViewModel和PersonViewModel)是抽象的,因为必须存在一个由派生类中实现,并提供一个模型实例这些基类的抽象属性。
  • Model属性不应在基类的构造函数访问,因为构造函数链从基类进入到最派生类。 最派生类的构造函数将设置模式,所以基类构造函数的调用提前看到它。 这可以通过使模型作为通过构造一个参数来避免。
  • BusinessObject的和Person性质是不必要由派生类看出。 EditorBrowsableAttribute可能会帮助这里的智能感知,但只有当代码是由不同的Visual Studio解决方案的另一个组件中使用(这是Visual Studio的具体行为)。
  • 性能。 当基类访问模型,代码将经过虚拟性质的链。 但自从实施抽象属性被标记为封,虚拟表查找不应该这么多的性能退化。
  • 不能很好地扩展。 对于深的类层次结构的代码将包含许多不必要的成员。

另一种方法是:

public class BusinessObjectViewModel : ViewModelBase
{
    protected BusinessObject Model { get; private set; }

    public BusinessObjectViewModel(BusinessObject model)
    {
        this.Model = model;
    }
}

public class PersonViewModel : BusinessObjectViewModel
{
    protected new Person Model { get { return (Person)base.Model; } }

    public PersonViewModel(Person model)
        : base(model)
    {
    }
}

public class CustomerViewModel : PersonViewModel
{
    protected new Customer Model { get { return (Customer)base.Model; } }

    public CustomerViewModel(Customer model)
        : base(model)
    {
    }
}

public class EmployeeViewModel : PersonViewModel
{
    protected new Employee Model { get { return (Employee)base.Model; } }

    public EmployeeViewModel(Employee model)
        : base(model)
    {
    }
}

优点:

  • 基类并不需要是抽象的。
  • 模型可以通过基类构造来访问。
  • 不需要额外的属性。

缺点:

  • 铸件。

基于这种分析,我将与第二个选项去,因为固定它唯一的缺点,铸造性能,是不必要的微观优化,将不会在WPF背景明显。



Answer 2:

最简单的答案是IMO使用泛型,这可能是那样简单

public abstract class ViewModelBase<TModel>  TModel : class{
    public TModel Model { get; protected set; }
}

在.NET打字系统将知道你的TModel是一个人,客户,或任何其他没有铸造。

让我知道如果你需要更多的,或者如果你想发布一些代码,需要帮助。 是的,它可能会非常棘手让你的超heirarchies正好在第一。

HTH,
Berryl



Answer 3:

如果你只是想揭露你的ViewModels模型属性,那么你也不需要重新申报的视图模型的模型属性来揭露他们。 我常露出下方的Model对象在我的ViewModels的属性。 在你的情况下,例如在你EmployeeViewModel你将有一个:

private Employee _MyEmployee;
public Employee MyEmployee {
get
{
return _MyEmployee;
}
set
{
_MyEmployee = value;
NotifyPropertyChanged(x=>x.MyEmployee);
}

然后你的视图可以通过在视图模型暴露将myEmployee属性绑定到你的员工属性。 据我所知,唯一的情况下,当你要重新申报或包裹在你的虚拟机的模型属性是当你需要做一些数据操作将呈现给您的视图。



文章来源: viewmodel inheritance and duplicate model references