看起来ViewModel包含一组模型,它们被设置为视图的datacontext。
在MVVM中,ViewModel不应该是视图的datacontext,Model会修改ViewModel,然后会影响View吗?
答案 0 :(得分:5)
TL; DR - 这个例子根本不是MVVM。
是的,它是MVVM的一个糟糕的例子。视图在运行时绑定到查询“viewmodel”中的属性而不是绑定到viewmodel本身的LINQ结果。其他任何地方都没有使用Accomplishments
。
换句话说,OP指向的示例中的,视图根本没有绑定到viewmodel,而是错误地直接绑定到模型集合。我不相信ObservableCollection<>
构成合理的ViewModel。 (或IEnumerable<>
; IList<>
或类似的)
这是视图代码隐藏中的违规行:
LevelViewOnPage.DataContext = from Accomplishment in vm.Accomplishments
where Accomplishment.Type == "Level"
select Accomplishment;
通常,您会将视图的DataContext
绑定到viewmodel。
代码审核 - 它实际上非常可怕,有一些奇怪的设计和命名约定。
视图通过以下方式调用视图模型:
vm.GetAccomplishments();
...由于它是void
,因此不会“获取”任何内容。如果您的订单错误,该方法会填充您必须阅读的Accomplishments
属性,这太糟糕了。
答案 1 :(得分:2)
如果你遵循SOLID principles of object oriented programming,那将给ViewModel带来多个改变的理由。模型就是这样 - 一个模型,一个零智能的愚蠢对象。
ViewModel的责任仅仅是保持可视化的状态,例如显示Person的当前值,并将任何更改中继到正确的底层服务类。
无论如何,ViewModel就是动作发生的地方。
Order / OrderLines的无休止示例,其中构建一个ViewModel,其中包含您要进一步显示的所有属性,这表明ViewModel是关于协调要在视图中显示的对象并促进与你的其余代码
ViewModel通常还会扩展视图的属性,以便您可以在LoginViewModel中具有如下所示的属性:
public class LoginViewModel : INotifyPropertyChanged
{
public string Username{get;set;}
public string Password{get;set;}
public bool CanLogin {
get{
return Username.Length > 0 && Password.Length > 0;
}
}
}
在上面的课程中,您现在可以对&#34; CanLogin &#34;进行数据绑定。属于您的&#34;已启用&#34;视图中的属性,以便只有在用户名和密码具有值时才能按下按钮,即使&#34; CanLogin&#34;不属于模型的一部分。
然而,最大的争论是ViewModel已经有太多的责任,因为它既提供了对模型的所有属性的访问(责任1),也促进了一些代码逻辑(即调用&#34) ; UpdatePerson&#34;来自某个PersonService类),这违反了单一责任原则。出于这个原因,并且为了保持清晰的关注点分离,我经常创建两个不同级别的ViewModel - 级别1是到模型的纯映射,这基本上只是给我的模型一个INotifyPropertyChanged所有模型的公共属性在第二级,我创建ViewModel,它与底层服务类进行一些交互(例如&#34; VerifyPassword()&#34;,&#34; UpdatePerson()&#34;等。