集合的MVVM

时间:2011-06-10 08:25:01

标签: wpf mvvm

我最近开始学习wpf并尝试使用mvvm。

我的理解是,在mvvm中,视图或模型都不应该知道另一个存在。

我要做的是在屏幕上显示客户列表。但是如果我对viewModel进行编码,如下所示。这与我在网上看到的许多例子类似,然后我最终得到了一些看起来像这样的代码

class Customer 
{    
    public String Name {get;set;}     
    public String Address {get;set;} }
}

class MainWindowViewModel
{
    ObservableCollection<Customer> customers = new ObservableCollection<Customer>();

    public ObservableCollection<Customer> Customer 
    {
      get {return customers;}
    } 

    public MainWindowViewModel() 
    {
     //cust1 and cust2 are Customer objets
      customers.Add(cust1);
      customers.Add(cust2);
    }
}

现在,如果我创建 MainWindowViewModel 的实例并将其设置为我的 MainWindowView (我的视图)的datacontext,并进一步绑定viewmodels Customers < / strong>属性为listBox,然后视图将需要对包含我的模型的程序集的引用。

所以我的问题是。

1)在MVVM中添加对允许的模型程序集的引用,因为这意味着视图知道模型。

2)更好的解决方案是将每个 Customer 对象包装在 CustomerViewModel 中,让MainWindowViewModel包含 CustomerViewModel的ObservableCollection 而不是客户的ObservableCollection 。这会将模型与视图完全分开。

5 个答案:

答案 0 :(得分:3)

  1. 我不确定为什么您认为包含您的观点的项目需要参考您的模型项目?您的视图中没有任何内容直接引用您的模型 - XAML中的绑定表达式仅按名称链接,而是链接到视图模型上的属性,而不是您的模型。
  2. 如果您的视图需要比模型提供的更多数据,则在视图模型中包装模型是一个不错的选择,并且不希望更改模型。例如,您可能需要显示Age类型的User,但User只有DateOfBirth属性。如果您不想更改模型,则创建具有UserViewModel属性的Age将是一个不错的选择。

答案 1 :(得分:2)

您的问题的答案:

  1. 参考模型的视图有什么不好?这在简化代码时绝对可以。反过来说(模型 - &gt;视图)是不好的做法。

  2. 当您没有特殊需求时,您无需将每个客户对象包装在 CustomerViewModel 中。我建议采用务实的方式并保持代码简单。

  3. 您可能会对 WPF Application Framework (WAF) BookLibrary 示例应用感兴趣,该应用会显示您在此处描述的方案。

答案 2 :(得分:0)

我们通常会创建一个CustomerViewModel。这是由我们的通用CollectionViewModelBase类强制执行的。这不确定用户界面使用的每个部分都是特别创建的以便显示,并且我们在模型中没有任何与UI相关的代码,这些代码通常是可序列化的POCO。

答案 3 :(得分:0)

MVVM模式类似于任何其他MVx模式(MVC,MVP,...),因为它鼓励关注点分离(SoC),从而提高代码的可维护性/可测试性。除了通常的SoC之外,MVVM还提供以下内容:

  1. 视图逻辑的单元测试;这是因为您将视图中的逻辑移动到视图模型中,使您的视图尽可能愚蠢。
  2. 开发者 - 设计师工作流程;因为视图是“愚蠢的”,所以在没有背后的逻辑的情况下使用XAML更容易。
  3. 关于可见性,即什么是可见的,严格如下:

    Model <= ViewModel <= View
    

    换句话说,ViewModel可以看到Model,但Model看不到ViewModel。同样,View可以看到ViewModel,但反之亦然。

    因为ViewModel没有对View的引用,所以它可以在没有任何视图组件的情况下执行代码,这将启用上面的(1)。

    ViewModel的目的是“塑造”您的模型以更轻松地绑定到View。如果您的视图很简单,那么执行以下操作是完全可以接受的:

    Model <= View
    

    这仍然允许(1)单元测试,(2)开发人员 - 设计师工作流程。

    使用混合方法也很好,有时会将模型暴露给您的视图,有时将其包装在ViewModel中。例如:

    http://www.scottlogic.co.uk/blog/colin/2009/08/the-mini-viewmodel-pattern/

    请不要创建一堆样板的ViewModel代码,只是因为您认为必须这样做!

答案 4 :(得分:0)

您肯定希望仅在视图中包装模型,如下所示:

/// <summary>
/// Business model object : Should be in your separate business model only library
/// </summary>
public class BusinessModelObject
{
    public string Prop1 { get; set; }
    public int Prop2 { get; set; }
}



/// <summary>
/// Base notifying object : Should be in your GUI library
/// </summary>
public abstract class NotifyingObject<T> : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, e);
    }


    private static readonly PropertyChangedEventArgs ModelPropertyChanged = new PropertyChangedEventArgs("Model");
    private T _model;
    public T Model
    {
        get { return _model; }
        set
        {
            _model = value;
            NotifyPropertyChanged(ModelPropertyChanged);
        }
    }
}

/// <summary>
/// Model decorator : Should be in your GUI library
/// </summary>
public class BusinessModelObjectAdapter : NotifyingObject<BusinessModelObject>
{
    public BusinessModelObjectAdapter(BusinessModelObject model)
    {
        this.Model = Model;
    }

    private static readonly PropertyChangedEventArgs Prop1PropertyChanged = new PropertyChangedEventArgs("Prop1");
    private string _prop1;
    public string Prop1
    {
        get { return Model.Prop1; }
        set
        {
            Model.Prop1 = value;
            NotifyPropertyChanged(Prop1PropertyChanged);
        }
    }

    private static readonly PropertyChangedEventArgs Prop2PropertyChanged = new PropertyChangedEventArgs("Prop2");
    private int _prop2;
    public int Prop2
    {
        get { return Model.Prop2; }
        set
        {
            Model.Prop2 = value;
            NotifyPropertyChanged(Prop1PropertyChanged);
        }
    }

    //and here you can add whatever property aimed a presenting your model without altering it at any time
}