我最近开始学习wpf并尝试使用mvvm。
我的理解是,在mvvm中,视图或模型都不应该知道另一个存在。
我要做的是在屏幕上显示客户列表。但是如果我对viewModel进行编码,如下所示。这与我在网上看到的许多例子类似,然后我最终得到了一些看起来像这样的代码
class Customer
{
public String Name {get;set;}
public String Address {get;set;} }
}
class MainWindowViewModel
{
ObservableCollection<Customer> customers = new ObservableCollection<Customer>();
public ObservableCollection<Customer> Customer
{
get {return customers;}
}
public MainWindowViewModel()
{
//cust1 and cust2 are Customer objets
customers.Add(cust1);
customers.Add(cust2);
}
}
现在,如果我创建 MainWindowViewModel 的实例并将其设置为我的 MainWindowView (我的视图)的datacontext,并进一步绑定viewmodels Customers < / strong>属性为listBox,然后视图将需要对包含我的模型的程序集的引用。
所以我的问题是。
1)在MVVM中添加对允许的模型程序集的引用,因为这意味着视图知道模型。
2)更好的解决方案是将每个 Customer 对象包装在 CustomerViewModel 中,让MainWindowViewModel包含 CustomerViewModel的ObservableCollection 而不是客户的ObservableCollection 。这会将模型与视图完全分开。
答案 0 :(得分:3)
Age
类型的User
,但User
只有DateOfBirth
属性。如果您不想更改模型,则创建具有UserViewModel
属性的Age
将是一个不错的选择。 答案 1 :(得分:2)
您的问题的答案:
参考模型的视图有什么不好?这在简化代码时绝对可以。反过来说(模型 - &gt;视图)是不好的做法。
当您没有特殊需求时,您无需将每个客户对象包装在 CustomerViewModel 中。我建议采用务实的方式并保持代码简单。
您可能会对 WPF Application Framework (WAF) 的 BookLibrary 示例应用感兴趣,该应用会显示您在此处描述的方案。
答案 2 :(得分:0)
我们通常会创建一个CustomerViewModel。这是由我们的通用CollectionViewModelBase类强制执行的。这不确定用户界面使用的每个部分都是特别创建的以便显示,并且我们在模型中没有任何与UI相关的代码,这些代码通常是可序列化的POCO。
答案 3 :(得分:0)
关于可见性,即什么是可见的,严格如下:
Model <= ViewModel <= View
换句话说,ViewModel可以看到Model,但Model看不到ViewModel。同样,View可以看到ViewModel,但反之亦然。
因为ViewModel没有对View的引用,所以它可以在没有任何视图组件的情况下执行代码,这将启用上面的(1)。
ViewModel的目的是“塑造”您的模型以更轻松地绑定到View。如果您的视图很简单,那么执行以下操作是完全可以接受的:
Model <= View
这仍然允许(1)单元测试,(2)开发人员 - 设计师工作流程。
使用混合方法也很好,有时会将模型暴露给您的视图,有时将其包装在ViewModel中。例如:
http://www.scottlogic.co.uk/blog/colin/2009/08/the-mini-viewmodel-pattern/
请不要创建一堆样板的ViewModel代码,只是因为您认为必须这样做!
答案 4 :(得分:0)
您肯定希望仅在视图中包装模型,如下所示:
/// <summary>
/// Business model object : Should be in your separate business model only library
/// </summary>
public class BusinessModelObject
{
public string Prop1 { get; set; }
public int Prop2 { get; set; }
}
/// <summary>
/// Base notifying object : Should be in your GUI library
/// </summary>
public abstract class NotifyingObject<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, e);
}
private static readonly PropertyChangedEventArgs ModelPropertyChanged = new PropertyChangedEventArgs("Model");
private T _model;
public T Model
{
get { return _model; }
set
{
_model = value;
NotifyPropertyChanged(ModelPropertyChanged);
}
}
}
/// <summary>
/// Model decorator : Should be in your GUI library
/// </summary>
public class BusinessModelObjectAdapter : NotifyingObject<BusinessModelObject>
{
public BusinessModelObjectAdapter(BusinessModelObject model)
{
this.Model = Model;
}
private static readonly PropertyChangedEventArgs Prop1PropertyChanged = new PropertyChangedEventArgs("Prop1");
private string _prop1;
public string Prop1
{
get { return Model.Prop1; }
set
{
Model.Prop1 = value;
NotifyPropertyChanged(Prop1PropertyChanged);
}
}
private static readonly PropertyChangedEventArgs Prop2PropertyChanged = new PropertyChangedEventArgs("Prop2");
private int _prop2;
public int Prop2
{
get { return Model.Prop2; }
set
{
Model.Prop2 = value;
NotifyPropertyChanged(Prop1PropertyChanged);
}
}
//and here you can add whatever property aimed a presenting your model without altering it at any time
}