The Model in MVVM
It's taken 4 months, but I've finally got round to watching my tech-ed talk from back in August. It's funny, because I remember feeling a bit flat at the end of the talk - but watching it back, I actually think I got my points across fairly well*
If you can't be arsed watching the whole hour (and shame on you!) let's just skip to the end of the talk. I was asked "How come MVVM talks always neglect to mention the Model" - and I had indeed fallen into this trap, but in my defense
- The model in the MVVM pattern is no more special than the model in MVC and that's been around since the 1970's, so there's an assumption that you know what a Model is and does, and
- The slide deck I had used for my practise-run at the local DNUG contained a slide headed "What about the Model?" - so I had given this some thought, honest!
My response to the question remains my opinion today, namely - the model contains domain-level business rules and the ViewModel contains all the logic and assets (properties and commands) required to furnish the view. Here is the example:
Use Case: A user is attempting to change an application password. They are presented with a screen that contains 3 input fields ("Old Password", "New password" and "Confirm new password") and two buttons ("OK" and "Cancel")
So in this example, the underlying domain object is a User that probably looks something like this (skipping over the issue of keeping a password as plain-text in an in-memory object instance):
public class User
{
public string UserName { get; private set; }
public string Password { get; private set; }
public void SetPassword(string newPassword)
{
// Implement domain-specific business rules here.
// e.g. 'Must be 10 characters long', or 'Must contain letters and numbers only'
// Persist the new password only if these rules are satisfied.
}
}
But up in the View, we need to do a couple of other things, too - firstly, we need to make sure the old password is correct for the username, and secondly, we need to make sure that the 'new password' field matches exactly the 'confirm new password' field.
public class ChangePasswordViewModel : ViewModelBase
{
private readonly User _user;
public string OldPassword { get; set; }
public string NewPassword { get; set; }
public string ConfirmPassword { get; set; }
public ICommand OkCommand { get; private set; }
public ChangePasswordViewModel(User user)
{
_user = user;
OkCommand = new RelayCommand(OkHandler);
}
private void OkHandler()
{
if (_user.Password != OldPassword) throw new Exception("Wrong password for user");
if (NewPassword != ConfirmPassword) throw new Exception("Passwords must match");
// Pass the new password into the User
_user.SetPassword(NewPassword);
}
}
Now these are quite plainly not domain-concerns, but View-concerns. As far as the 'User' object cares, you can enter any combination of (valid) characters into the password field. The 'confirm new passsword' field only exists, because the typed characters of the 'new password' input field are not visible as characters, and we want to ensure the user has typed the new password correctly. If the two new password fields don't match, then we're not going to persist the new password - even if it matches the domain rules. In other words, we have another layer of validation in the ViewModel, carrying equal importance as the validation in the model.
That's what I think, anyway. Leave a comment to let me know if you agree or disagree - would love to hear your opinion.
(*) To the person who put on their feedback "What is MVVM? I'm confused" - If you don't get it after that talk, then perhaps you shouldn't be doing it, cos I got no way of explaining it any clearer...


Comments
No comments yet. Be the first!