how to correctly define Model to ViewModel relatio

2019-05-05 17:07发布

问题:

I trying to understand Model to ViewModel relation and I keep bumping in the same problem. Assuming we have a "Person" class with just one field:

public class Person
{
   public string Name;
}

In the next phase I have my XAML artist who created a user control that present a Person and he according to practice of MVVM need to relate his view to VMPerson (View-Model Person), so now I add another class:

public class VMPerson : INotifyPropertyChange
{
   private Person person;

   public VMPerson():this(new Person()){}

   public VMPerson(Person person)
   {
      this.person = person;
   }

   public Name
   { get { return person.name; }
   { set { person.name = value; PropertyChange("Name"); }
}

So now I have almost everything setup.. but how would my VM class relate to changes in my model class?? if I add INotifyPropertyChanged and add a property for "Name" in the model I endup with something very similar to my ViewModel class an extra layer which I will not need. Is there any way to keep my Model class as it is and still be notified on changes inside it in the view-model class? if there is no other way than using INotifyPropertyChanged mechanism or anything similar which will be implemented in the model why do I need VM ?? is it just for a situation that aggregate few "model" classes into one class which will be served to the View?

I think I must be missing something in my understanding cause it seems to me according to what I described that a Model to View pattern while using the View code-behind as a controller would be better abstraction than MVVM, but I certainly not sure about that. Can someone explain to me what I am missing? thanks.

回答1:

Putting the viewmodel code into the model is not the best idea

It's true that viewmodels in many cases begin life by looking like extra layers of code that don't really add anything of value, but the point is that they can evolve.

The role of a VM is to provide convenience to views -- INotifyPropertyChanged is one such convenience while the role of a model is to encapsulate your business logic. As the functionality of your code grows the will keep getting richer; at some point, it might even end up being much larger in code size than your model. So the distinction is made in order that the convenience and the business logic parts are kept nicely separated from each other, which has a good effect on the maintainability of your code.

Putting the viewmodel code into the view is not the best idea

The reason here is different: if you do this and then need to use the viewmodel with another type of view, you will have to duplicate all the logic into the other view's codebehind as well. Duplication is bad; DRY is good.

Considering that a very important feature of MVVM is that it affords testability and that testability necessarily means at least two types of views (the real one and the mock), the necessity of this approach becomes evident.



回答2:

One purpose of the viewmodel is to take data from the model, process it the way the data must be visualized.

For example in your model you could have the information DateOfBirth and you want to visualize the actual age.

In this case you should do the processing (conversion DateOfBirth to actual age, something like DateTime.Now.Year - DateOfBirth.Year) in the ViewModel.

In your specific case the ViewModel is just a wrapper (no processing) for the data from the model and appareantly there is no need for the Viewmodel.

In order to get model changes in the ViewModel (for properties that do not need processing in VM) I usually implement INotifyPropertyChanged also in the model. This avoids a lot of wrapper properties in the ViewModel.

In my ViewModel I will have somethink like

_model.PropertyChanged += PropertyChangedEventHandler(OnPropertyChangedModel);

void OnPropertyChangedModel(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    OnPropertyChanged(e.PropertyName);
}

Note that in this case the model properties are directly sent to the View (no processing in the ViewModel).



回答3:

The way I look at it is as follows: - ViewModel, this is like Presenter in old MVP in a way, it will contain & join various business functionalities (like consuming of IDealService and IStaticDataService).

Model for me is very close to DataModel which simply repesents the data.

If VM has too many data related bits, i usually move them into Model and use the instance of it from VM.

i.e. you could have:

public class VMPerson : INotifyPropertyChange
{
   public Person PersonItem {get; set;}

   public VMPerson()
   {
      PersonItem = new Person();
   }
}

and you can still get to Person's name in your via: {Binding PersonItem.Name}

I agree it will be difficult to make it Notifiable that if your origianl Person class doesnt inherit INPC.