What do you do when you have Rich Models?
I'm working with existing code in a project which has rich models all over the place (instead of POCOs). Basically, is there any good way to mix rich models and ViewModels without repeating code?
- The rich models have data validation. Any easy way to reuse these with the ViewModels?
Example:
public class PersonViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private Person _person;
[Required] //This seems redundent...
public String FirstName { ... }
}
public class Person
{
[Required]
public String FirstName { ... }
}
That's just one example... basically, if you have a Rich Model is there any way to take advantage of that while maintaining MVVM and avoid redundent code开发者_StackOverflow社区? I'd really like to avoid having my Models be any data context or fully exposed by the ViewModel.
For example:
public class PersonViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private Person _person;
//This seems like a bad thing to do...
public Person ThePerson { get { return _person; } }
}
This is something of a classic question.
If you "pollute" your Model classes with presentation-layer-specific interfaces and attributes, you gain efficiency by only having one version of any logical model, but lose the ability for the presentation and business model to evolve independently.
If you keep your Model "pure" and maintain a separate View Model, you gain flexibility in each, but lose efficiency due to having to maintain (and map between) two versions.
From a theory perspective, and for more complex systems, I would recommend the latter. If your system is relatively simple (think CRUD) and you don't expect to need to have the two types of models evolve independently, you are probably pretty safe with the former.
Obviously, the two methods are not mutually exclusive, and making the decision on a screen by screen basis is not unheard of.
One idea of MVVM is to separate the presentation layer from the data layer. This gives you the ability to change the data the presentation layer is working with without changing the data layer's data.
The data from the presentation layer thus is only written to your data layer on user request. Your redundant FirstName property works as a layer border that gives you the flexibility to implement something like a simple "undo all changes".
Consider using a generic ValueViewModel that handles the notification on value changes as they are required by data binding. Following this approach your view model will look something like:
public class PersonViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private Person _person;
[Required] //This seems redundent...
public ValueViewModel<String> FirstName { ... }
}
Using this pattern your model does not need to implement the INotifyPropertyChanged interface what again separates your presentation layer from your data layer.
MVVM is a very toplofty pattern and you will often see things that on the first view seem a bit formal, but following the pattern gives you great flexibility. If you choose to violate the MVVM rules you put your whole application architexture at stake because this one violation destroyes the flexibility you gained using mvvm. Thus if you plan to violate MVVM, think about not using it at all.
I've never seen anything wrong with exposing entire Model's from the ViewModel for the View. I know it's not the "MVVM-Purist" approach, but it is simple, fast, and it works well.
But I do understand that both methods are equally valid, and usually for a very large code-base that separation between Model and ViewModel makes life easier in the long run. In that case, why not have your ViewModel validation return your ModelValidation? It's not as pretty as using DataAnnotations, but you wouldn't be creating your validation in multiple spots.
For example, I often use something like this:
public string GetValidationError(string propertyName)
{
string s = null;
switch (propertyName)
{
case "FirstName":
case "LastName":
s = Person.GetValidationError(propertyName);
break;
}
return s;
}
string IDataErrorInfo.this[string propertyName]
{
get { return this.GetValidationError(propertyName); }
}
精彩评论