标准的“模型视图控制器”模式和微软的模型/视图/视图模型模式之间有区别吗?
当前回答
MVVM将视图模型添加到混合中。这很重要,因为它允许您大量使用WPF的绑定方法,而无需将所有特定于UI的部分放在常规模型中。
我可能是错的,但是我不确定MVVM真的强迫控制器混合。我发现这个概念更符合:http://martinfowler.com/eaaDev/PresentationModel.html。我认为人们选择将其与MVC结合起来,而不是将其内置到模式中。
其他回答
简而言之,在MVC控制器中,ViewModel知道(控件)视图,而在MVVM中,ViewModel不知道谁使用它。ViewModel将其可观察属性和操作公开给任何可能对使用它感兴趣的人。这一事实使得测试更容易,因为在ViewModel中没有对UI的引用。
MVC是受控环境,MVVM是响应式环境。
在受控的环境中,你应该有更少的代码和一个通用的逻辑源;它应该始终存在于控制器中。然而;在web世界中,MVC很容易被分为视图创建逻辑和视图动态逻辑。创建在服务器上,动态在客户端上。你在ASP中经常看到这种情况。与AngularJS结合在一起,而服务器将创建一个视图并传入一个模型并将其发送给客户端。然后客户端将与视图交互,在这种情况下,AngularJS将作为本地控制器介入。一旦提交模型或新模型,就会被传递回服务器控制器并进行处理。(因此循环继续,当使用套接字或AJAX等时,这种处理有很多其他的翻译,但总体上架构是相同的。)
MVVM是一个响应式环境,这意味着您通常编写的代码(例如触发器)将基于某些事件激活。在MVVM蓬勃发展的XAML中,使用内置的数据绑定框架可以轻松完成这一切,但如前所述,这将适用于任何视图、任何编程语言的任何系统。它不是多发性硬化症特有的。ViewModel会触发(通常是属性改变事件),View会根据你创建的触发器对它做出反应。这可能是技术性的,但底线是视图是无状态的,没有逻辑。它只是基于值更改状态。此外,viewmodel是无状态的,逻辑很少,而模型是逻辑本质为零的状态,因为它们应该只维护状态。我将其描述为应用程序状态(模型)、状态转换器(ViewModel),然后是可视状态/交互(视图)。
在MVC桌面或客户端应用程序中,你应该有一个模型,该模型应该由控制器使用。基于模型,控制器将修改视图。视图通常与带有接口的控制器绑定,以便控制器可以使用各种视图。在ASP。NET中的MVC逻辑在服务器上略微向后,因为控制器管理模型并将模型传递给选定的视图。然后,视图会根据模型填充数据,并拥有自己的逻辑(通常是另一个MVC集,例如用AngularJS完成的)。人们会争论并将其与应用程序MVC混淆,并试图同时做这两件事,而维护项目最终将成为一场灾难。使用MVC时,总是把逻辑和控件放在一个位置。不要在视图后面的代码中(或通过web的JS在视图中)写视图逻辑来容纳控制器或模型数据。让控制器改变视图。视图中应该存在的唯一逻辑是通过它所使用的接口创建和运行所需的任何逻辑。提交用户名和密码就是一个例子。无论是桌面还是网页(在客户端),只要视图触发提交动作,控制器就应该处理提交过程。如果做得正确,你总是可以很容易地找到MVC web或本地应用程序。
MVVM是我个人最喜欢的,因为它完全是反应性的。如果模型改变了状态,ViewModel会监听并转换状态,就这样!!然后,视图监听ViewModel的状态变化,并根据来自ViewModel的转换进行更新。有些人称之为纯粹的MVVM,但实际上只有一个,我不在乎你怎么争论,它总是纯粹的MVVM,其中视图完全不包含逻辑。
这里有一个小例子:假设你想要在按下按钮时滑动菜单。在MVC中,你的界面中会有一个MenuPressed动作。当你点击菜单按钮时,控制器会知道,然后告诉视图根据另一个接口方法(如SlideMenuIn)在菜单中滑动。为什么要往返?如果控制器决定你不能或想要做别的事情,这就是原因。控制器应该负责视图,视图什么都不做,除非控制器这么说。然而;在MVVM中,动画中的幻灯片菜单应该是内置的和通用的,而不是被告知滑动它将基于一些值这样做。它监听ViewModel当ViewModel说IsMenuActive = true时动画就会发生。现在,说到这里,我想非常清楚地说明另一点,请注意。IsMenuActive可能是糟糕的MVVM或ViewModel设计。在设计ViewModel时,你永远不应该假设视图会有任何特性,而只是传递转换后的模型状态。这样,如果你决定更改视图以删除菜单,只是以另一种方式显示数据/选项,ViewModel不会关心。那么您将如何管理菜单呢?当数据有意义时,就是这样。因此,一种方法是给菜单一个选项列表(可能是内部ViewModels的数组)。如果该列表有数据,菜单就知道通过触发器打开,如果没有,它就知道通过触发器隐藏。你只是在ViewModel中有菜单的数据。不要决定在ViewModel中显示/隐藏数据。简单地转换模型的状态。通过这种方式,视图是完全响应式和通用的,可以在许多不同的情况下使用。
如果你还不熟悉它们的架构,那么这一切可能完全没有意义,因为你会在网上发现很多不好的信息,学习起来可能会非常混乱。
所以…要做到这一点,需要记住以下几点。预先决定如何设计应用程序,并坚持下去。
如果你使用MVC,这很好,那么确保你的控制器是可管理的,并完全控制你的视图。如果你有一个大的视图,可以考虑在视图中添加具有不同控制器的控件。只是不要将这些控制器级联到不同的控制器上。维护起来非常令人沮丧。花点时间把东西分开设计,让它们作为独立的组件工作……并且总是让控制器告诉模型提交或持久化存储。MVC的理想依赖设置是视图←控制器→模型或ASP。模型←视图↔控制器→模型(从控制器到视图,模型可以相同,也可以完全不同)…当然,此时唯一需要知道的是视图中的控制器,主要是为了端点参考,以知道在哪里返回传递模型。
如果你做MVVM,我祝福你善良的灵魂,但要花时间做对!不要使用接口。让视图根据值来决定它的外观。使用模拟数据处理视图。如果你最终有一个视图显示你的菜单(如例),即使你不想要它的时候,那么好。你的视图按照它应该的方式工作,并根据它应该的值做出反应。只需向触发器添加一些需求,以确保ViewModel处于特定的转换状态时不会发生这种情况,或者命令ViewModel清空该状态。在你的ViewModel中,不要用内部逻辑删除它,就好像你在决定视图是否应该看到它一样。记住,你不能假设ViewModel中有或没有菜单。最后,模型应该允许您更改和存储状态。这是验证和所有事情发生的地方;例如,如果模型不能修改状态,那么它将简单地将自己标记为脏或其他东西。当ViewModel意识到这一点时,它会转换脏的东西,然后视图会意识到这一点,并通过另一个触发器显示一些信息。视图中的所有数据都可以绑定到ViewModel,因此一切都可以是动态的,只有模型和ViewModel完全不知道视图将如何对绑定做出反应。事实上,模型也没有ViewModel的概念。当设置依赖项时,它们应该这样指向,而且只这样指向View→ViewModel→Model(这里还有一个边注…这可能也会引起争论,但我不在乎……不要将模型传递给视图,除非该模型是不可变的;否则用适当的ViewModel包装它。视图不应该看到模型周期。我说你看过什么演示或者你是怎么做的,这是错误的。)
这是我的最后一个建议……看看一个设计良好但非常简单的MVC应用程序,并对MVVM应用程序进行同样的操作。一个将有更多的控制,限制到零灵活性,而另一个将没有控制和无限的灵活性。
受控环境非常适合从一组控制器或(单个源)管理整个应用程序,而响应式环境可以被分解为单独的存储库,完全不知道应用程序的其余部分在做什么。微观管理vs自由管理。
如果我还没有把你弄糊涂,试着联系我……我不介意用插图和例子详细讨论这个问题。
在一天结束的时候,我们都是程序员,当我们编码的时候,我们内心就会出现混乱……所以规则会被打破,理论会改变,所有这些最终都将成为垃圾……但在大型项目和大型团队中工作时,就设计模式达成一致并实施它确实很有帮助。总有一天,它会让你开始时多迈出的一小步,在以后变成一笔突飞猛进的积蓄。
首先,MVVM是使用XAML处理显示的MVC模式的发展。本文概述了这两者的一些方面。
模型/视图/视图模型架构的主要目的似乎是在数据(“模型”)之上,还有另一层非可视组件(“视图模型”),它将数据的概念更紧密地映射到数据的视图(“视图”)的概念。视图绑定的是ViewModel,而不是直接绑定模型。
使用MVC将强类型视图模型注入到视图中
控制器负责更新ViewModel并将其注入View中。(用于get请求) ViewModel是DataContext和视图状态(如最后选中的项目等)的容器。 模型包含数据库实体,非常接近数据库模式,它进行查询和过滤。(我喜欢EF和LINQ) 模型还应该考虑存储库和或将结果投影到强类型(EF有一个很好的方法……EF.Database。选择(querystring, parms)直接ADO访问注入查询和返回强类型。这解决了EF是缓慢的参数。EF并不慢! ViewModel获取数据并执行业务规则和验证 post后面的控制器将调用ViewModel post方法并等待结果。 控制器会将最新更新的视图模型注入到视图中。视图只使用强类型绑定。 视图仅仅呈现数据,并将事件发送回控制器。(参见下面的例子) MVC拦截入站请求,并将其路由到具有强数据类型的适当控制器
在这个模型中,不再有HTTP级别的与请求或响应对象的接触,因为MSFT的MVC机器对我们隐藏了它。
澄清上文第6项(应要求)…
假设ViewModel是这样的:
public class myViewModel{
public string SelectedValue {get;set;}
public void Post(){
//due to MVC model binding the SelectedValue string above will be set by MVC model binding on post back.
//this allows you to do something with it.
DoSomeThingWith(SelectedValue);
SelectedValue = "Thanks for update!";
}
}
这篇文章的控制器方法看起来像这样(见下文),注意mvm的实例是由MVC绑定机制自动实例化的。因此,您永远不必下拉到查询字符串层!这是MVC基于查询字符串为您实例化ViewModel !
[HTTPPOST]
public ActionResult MyPostBackMethod (myViewModel mvm){
if (ModelState.IsValid)
{
// Immediately call the only method needed in VM...
mvm.Post()
}
return View(mvm);
}
注意,为了让上面的actionmethod像你想要的那样工作,你必须定义一个空CTOR来初始化post中没有返回的东西。回发也必须回发那些发生变化的名称/值对。如果缺少名称/值对,MVC绑定引擎就会做正确的事情,而这根本不是什么!如果发生这种情况,你可能会发现自己说“我正在丢失回post的数据”…
这种模式的优点是ViewModel做了所有“杂乱”的工作,接口到模型/业务逻辑,控制器只是一个路由器。这是SOC在起作用。
MVVM模型-视图视图模型类似于MVC,模型-视图控制器
控制器被替换为ViewModel。ViewModel位于UI层下面。ViewModel公开视图所需的数据和命令对象。你可以把它想象成一个容器对象视图从它那里获取数据和动作。ViewModel从模型中提取数据。
Russel East写了一篇博客,详细讨论了为什么MVVM不同于MVC