这是一个基本的 MVVM 问题。
假设我有一个学生编辑器窗口,允许用户设置学生的付款方式(现金或支票)。为灵活起见,必须从服务器检索可能的付款方式,并且列表因学生的年龄而异,也可以更改。
问题是:
应该将可能的付款方式存储在哪里?模型还是视图模型?
如果是模型,当用户更改年龄时,谁应该下载新的支付方式列表?
模型应该在 MVVM 中包含什么内容和做什么?
这是一个基本的 MVVM 问题。
假设我有一个学生编辑器窗口,允许用户设置学生的付款方式(现金或支票)。为灵活起见,必须从服务器检索可能的付款方式,并且列表因学生的年龄而异,也可以更改。
问题是:
应该将可能的付款方式存储在哪里?模型还是视图模型?
如果是模型,当用户更改年龄时,谁应该下载新的支付方式列表?
模型应该在 MVVM 中包含什么内容和做什么?
模型是存放支付方法和与每种方法相关的业务规则的逻辑位置。一种方法是使用描述每种付款方式的枚举,并使用“switch”语句进行查询。
另一种设计结合了多态性的优势,可能看起来像这样......
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");
}
}
这个示例硬编码了两种方法:Cash 和 Credit Card,每个类都知道如何在依赖继承处理公共属性的同时完成其工作。这种方法避免了“切换”,并在每个类中封装了所有业务规则和方法。因此,模型只公开了 ViewModel 需要知道的内容,以便在项目控件中向用户展示各种支付方式。
当用户更改年龄时,您的 VM 可以刷新列表。
VM 的代码片段看起来像...
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
}
无论您使用哪种方法(枚举或多态),经验法则是“VM 是否绝对需要知道这一点?我可以在我的架构中利用继承和多态的 OO 优势吗?”
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.