1

This is a basic MVVM question.

Lets say that i have a student editor window which allows the user to set the student's payment method (cash or cheque). For flexibility, the possible payment methods must be retrieved from the server and the list varies on the student's age which can also be changed.

The questions are:

  1. where should the possible payments methods be stored? Model or view model?

  2. if model, when the user changes the age who should download the new list of payment methods?

what should the model contain and do in MVVM?

Dean Kuga
  • 11,878
  • 8
  • 54
  • 108
LostInComputer
  • 15,188
  • 4
  • 41
  • 49

2 Answers2

2

The Model is the logical place to house payment methods and the business rules associated with each method. One approach is to use an enumeration that describes each payment method and this is queried using 'switch' statements.

An alternate design incorporates the strengths of polymorphism, and might look like this...

public class Model
{
    private readonly List<PaymentMethod> _allPaymentMethods; 
    public Model()
    {
        // get payment types from the db
        // to populate master list
        _allPaymentMethods = new List<PaymentMethod> {new Cash(), new CreditCard()};
    }
    public List<PaymentMethod> GetPaymentMethods(int age)
    {
        List<PaymentMethod> result =
            _allPaymentMethods.Where(q => q.Age == age).ToList();
        return result;
    }
}
public abstract class PaymentMethod
{
    public string Name { get; protected set; }
    public int Age { get; protected set; }
    public abstract void ProcessPayment();
    public override string ToString()
    {
        return Name;
    }
}
public class CreditCard:PaymentMethod
{
    public CreditCard()
    {
        Name = "Credit Card";
        Age = 25;
    }
    public override void ProcessPayment()
    {
        Console.WriteLine("Thanks for using your card");
    }
}
public class Cash:PaymentMethod
{
    public Cash()
    {
        Name = "Cash";
        Age = 22;
    }
    public override void ProcessPayment()
    {
        Console.WriteLine("Thanks for paying cash");
    }
}

This sample hard codes two methods: Cash and Credit Card, and each class knows how to do its work while relying upon inheritance to handle the common attributes. This approach avoids the 'switch' and encapsulates all of the business rules and methods within each class. So the Model exposes only what the ViewModel needs to know in order to present the various payment methods to the user in an items control.

When the user changes their age, your VM can refresh the list.

A code snippet for the VM looks like...

public class ViewModel :INotifyPropertyChanged
{
    public ObservableCollection<PaymentMethod> Methods { get; set; }
    public ViewModel()
    {
        Model m = new Model();
        Methods = new ObservableCollection<PaymentMethod>(m.GetPaymentMethods(22));
    }
    #region INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string name)
    {
        var handler = System.Threading.Interlocked.CompareExchange
               (ref PropertyChanged, null, null);
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
    #endregion
}

Whichever approach you use (either enumeration or polymorphism), the rule of thumb is "Does the VM absolutely need to know about this? Can I leverage the OO strengths of inheritance and polymorphism into my architecture?"

Gayot Fow
  • 8,710
  • 1
  • 35
  • 48
  • Does this model also contain the student properties or is the student in its own model that is also managed by the VM? – LostInComputer Aug 04 '13 at 01:21
  • @LostInComputer, I try to achieve a high level of isolation in my design because it simplifies testing and mocking. So I would use the same approach for the student, i.e., placing the business rules inside the model and exposing to the VM as little as possible. Unit test the model, and mock it out to test the VM. – Gayot Fow Aug 04 '13 at 01:58
1

Well, in my opinion the model should contain the list of payment methods, while the VM should contain a list to bind to the view. Example, what I would do is to have a List<PaymentOptions> on the model and a BindingList<PaymentOptions> or ObservableCollection<PaymentOptions> for the VM.

Eduardo Bonet
  • 479
  • 6
  • 14
  • Hi, I updated the question to make the payment method dynamic – LostInComputer Aug 03 '13 at 14:29
  • You could still have a List of payment methods, and these payment method have a property for the age right? Then in the VM you slect the items form the list. Example: List _paymentMethods; BindingList _possiblemethods = _paymentMethods.Where(x=>x.Age>minimum_age) – Eduardo Bonet Aug 03 '13 at 14:32