开发者

MVVM for collections

I have recently started learning wpf and am trying to use mvvm.

My understanding is that in the mvvm neither the view or the model should know the other exists.

What I am trying to do is show a list of customers on the screen. But if I code the viewModel as shown below. which is similar to many examples I see on the net, then I end up with some code looking like this

class Customer 
{    
    public String Name {get;set;}     
    public String Ad开发者_StackOverflowdress {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);
    }
}

Now if I create an instance of my MainWindowViewModel and set it as the datacontext of my MainWindowView (my view) and i further bind the viewmodels Customers property to a listBox, then the view will need a reference to the assembly that contains my Models.

So my questions are.

1) Is adding a reference to Models assembly allowable in MVVM, since this would mean the view knows about the model.

2) would a better solution be to wrap each Customer object in a CustomerViewModel and have the MainWindowViewModel contain ObservableCollection of CustomerViewModel instead of ObservableCollection of Customer. This would separate the models completely from the view.


  1. I'm not sure why you think the project containing your views requires a reference to your model project? There is nothing in your view which references your models directly - your binding expressions in XAML are linked by name only, and to properties on your view model anyway, not your model.
  2. Wrapping your model in a view model is a good option if your view requires additional data than your model provides, and it is undesirable to change your model. For example, you view may need to display the Age of a User type, but User only has a DateOfBirth property. Creating a UserViewModel with an Age property would be a good option if you didn't want to alter your model.


Answers to your questions:

  1. What is bad about the View referring the Model? This is absolutely ok when it simplifies the code. Just the other way around (Model -> View) is bad practice.

  2. You don't need to wrap each Customer object in a CustomerViewModel when you don't have special needs. I would suggest to follow a pragmatic way and keep the code simple.

You might be interested in the BookLibrary sample application of the WPF Application Framework (WAF) which shows the scenario you describe here.


We usually create a CustomerViewModel. That is enforced by our generic CollectionViewModelBase class. This unsures that every part the user interface uses is exspecially created to be displayed and we don't have any UI related code in the models which are often serializable POCOs.


The MVVM pattern is similar to any other MVx pattern (MVC, MVP, ...) in that it encourages separation of concerns (SoC), which in turn improve maintainability / testability of your code. Beyond the usual SoC, MVVM gives the following:

  1. Unit testing of your view logic; this is because you move logic from your view into your view-model, making your view as dumb as possible.
  2. Developer-designer workflow; because the view is 'dumb', it is easier to work with the XAML without the logic behind it.

Regarding visibility, i.e. what is visible to what, it is strictly as follows:

Model <= ViewModel <= View

In other words, the ViewModel can see the Model, but the Model cannot see the ViewModel. Likewise, the View can see the ViewModel, but not vice-versa.

Because the ViewModel has no reference to the View, it enables your code to be executed without any view components present, this enables (1) above.

The purpose of your ViewModel is to 'shape' your Model to make binding to the View easier. If your View is simple, then it is quite acceptable to do the following:

Model <= View

This still allows (1) unit testing, (2) developer-designer workflow.

It is also fine to use a hybrid approach, sometimes exposing your Model to your view, other times wrapping it in a ViewModel. For example:

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

Please don't create a bunch of boiler-plate ViewModel code, just because you think you have to!


You will definitively want to wrap your models in view only objects like below :

/// <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
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜