viewmodel继承和重复模型引用

时间:2012-05-23 16:13:38

标签: c# wpf inheritance mvvm viewmodel

我的问题是:如何管理视图模型的继承链?

我的情况:

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

此外,我有一个 BusinessObjectViewModel ,它有一个Guid,一个 PersonBaseViewModel ,其中包含人员核心数据,一个 CustomerViewModel ,其中包含与客户相关的内容和一个 EmployeeViewModel 与员工相关的东西。

所有viewmodel肯定都封装了一个modelobject(Customer,Employee,PersonBase)。

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

模型通过构造函数进入viewmodel。

如果我使用构造函数链(每个viewmodel调用基础构造函数),每个viewmodel都有它的模型来从模型返回封装的值。

但是我必须在每个viewmodel中都有一个Model属性。在CustomerViewModel的情况下,我将在 CustomerViewModel 中引用一个引用,一个在PersonBaseViewModel中,一个在 BusinessObjectViewModel 中引用同一个对象。这听起来很愚蠢。

或者我必须在上部视图模型中转换每个属性访问。

P.S。这只是我模型层次结构的一小部分。

提前致谢。

3 个答案:

答案 0 :(得分:2)

最简单的答案IMO是使用Generics,这可能就像

一样简单
public abstract class ViewModelBase<TModel>  TModel : class{
    public TModel Model { get; protected set; }
}

.net输入系统会知道你的TModel是一个人,客户或其他没有铸造的东西。

如果您需要更多内容,或者您​​想发布一些需要帮助的代码,请告诉我们。是的,一开始就让你的超类型heirarchies恰到好处。

HTH,
Berryl

答案 1 :(得分: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属性提供值,并隐藏基类Model属性,因此每个VM都使用适当类型的Model属性(因此不需要强制转换)。 / p>

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

优点:

  • 不涉及施放。

缺点:

  • 仅当基类(BusinessObjectViewModel和PersonViewModel)是抽象类时才起作用,因为必须存在由派生类实现的抽象属性,并为这些基类提供Model实例。
  • 不应在基类构造函数中访问模型属性,因为构造函数链从基类转到最派生类。派生类最多的构造函数将设置Model,因此可以提前调用基类构造函数来查看它。通过构造函数将Model作为参数传递可以避免这种情况。
  • 派生类不需要看到BusinessObject和Person属性。 EditorBrowsableAttribute可能对Intellisense有帮助,但只有在不同的Visual Studio解决方案中另一个程序集使用代码时(这是Visual Studio特定的行为)。
  • 性能。当基类访问Model时,代码将通过一系列虚拟属性。但由于实现的抽象属性被标记为密封,因此虚拟表查找不应该降低性能。
  • 不能很好地扩展。对于深层次结构,代码将包含许多不必要的成员。

另一种方法是:

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环境中是不可察觉的。

答案 2 :(得分:0)

如果您只想在ViewModel中公开Model属性,则无需在ViewModel中重新声明Model属性以公开它们。我通常将底层的Model对象作为ViewModel中的属性公开。在您的情况下,例如在您的EmployeeViewModel中,您将拥有:

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

然后,您的View可以通过ViewModel中公开的MyEmployee属性绑定到您的Employee属性。据我所知,当您想要在VM中重新声明或包装模型属性时,唯一的情况是您需要进行一些数据操作才能呈现给您的视图。