原文背景
相对于 MVC 的历史来说,MVVM 是一个相当新的架构,MVVM 最早于 2005 年被微软的 WPF 和 Silverlight 的架构师 John Gossman 提出,并且应用在微软的软件开发中。该篇译文的原文即为John Gossman当年发布的博文。
翻译这篇文章,是期望在当今普遍地对MVX(该文主要说MVVM)相关模式片面理解的大环境下,让大家可以基于MVX最初提出,对我们对与MVX的实践应用以及MVX的本源思路进行一些思考。
文章关键技术名词简析
WPF :Windows Presentation Foundation,是微软推出的基于Windows 的用户界面框架,属于.NET Framework 3.0的一部分。
MVC :Model/View/Controller,模型/视图/控制器开发模式。
MVVM : Model/View/ViewModel,模型/视图/视图模型开发模式,是MVC的一个变种模式。
HTML :HyperText Markup Language,超文本标记语言,我们查看的网页的基础语言就是它。
XAML :eXtensible Application Markup Language,可扩展应用程序标记语言,是微软公司为构建应用程序用户界面而创建的一种新的描述性语言。
WYSIWYG :What You See Is What You Got,所见即所得,比如你在用美图秀秀处理图片的时候,图片处理完成展示的样子就是它最终的样子。(而不像用代码写视图一样,从代码中,外行人完全不知道最终展示的视图的样子)。
Dreamweaver :一款“所见即所得”的网页编辑器。
Flash : 一款“所见即所得”的动画编辑器。
Sparkle :另一款“所见即所得”的网页设计工具。
Smalltalk :公认的历史上第二个面向对象的程序设计语言(第一个是Simula 67)和第一个真正的集成开发环境 (IDE)。
Avalon :一个简单迷你的MVVM框架。
关系表 :原文中是relational tables,个人感觉理解为关系型数据库的数据表就没什么大问题了。
XML :eXtensible Markup Language,可扩展标记语言,经常用来描述进行通信的数据结构。(类似Json)
GUI :Graphical User Interface,图形用户界面。
触发器 :trigger,SQL server 提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程。它的执行不是由程序调用,也不是手工启动,而是由事件来触发。
单向绑定 :基于本文,是模型和视图的绑定,可以理解为模型数据变化触发视图更新。
双向绑定 :基于本文,是模型和视图的绑定,可以理解为模型数据变化触发视图更新,且视图操作触发模型数据更新。
bool :一个数据类型,其取值只能为0或1。
TextBox :文本框(翻译不需要太纠结)。
CheckBox,选择框,就是那个你在注册账号时候,注册协议旁边可以点击打钩的那种控件。(如图)
UI,User Interface,用户界面。
Assembly :.Net中反射机制的一个类封装。相关的数据结构有如下几个:AppDomain(应用程序域),Assembly(程序集类),Module(模块类),Type(使用反射得到的类型信息的最核心类)。它们之间的关系是:AppDomain包含多个Assembly,Assembly包含多个Module,Module包含多个Type。Assembly是有一个name属性的,该文中,举例的工程直接使用了Assembly数据结构。
ComboBox :下拉选框,点击了下拉框会弹出选择菜单的那种。(如图)
ListBox :列表,本文中的话,还是能滚的那种。(如图)
Library/Appearance/Project :文中直接对应举出的例子对应的三个面板,无需特别翻译。
MSBuild :Microsoft Build Engine 的缩写,基于该文,MSBuild Project的模型理解为一个已存在的,且不方便修改其属性定义的模型就够了。
译文正文
使用MVVM模式搭建WPF应用的方法介绍
MVVM是MVC模式的一个演变,针对一个视图的展示样式,比起传统的开发者,现在往往是设计师更为关注,MVVM正是为这种状况而定制的一种模式。一个设计师,往往更关注图形、艺术的呈现效果(传统的开发者则不会),他们常常使用声明式语言(如HTML,XAML)和WYSIWYG工具(所见即所得编辑器,如Dreamweaver,Flash,Sparkle)。简单地说,不同于后端逻辑或者后台数据,一个应用的UI部分常常会被不同的人使用各种各样的开发工具,各种各样的开发语言来完成开发。从MVC到MVVM促使了从Smalltalk到Web/Avalon这样一个转变,前者(smalltalk)只使用一种语言一套环境来开发一款应用,后者则为我们更为熟知的现代开发模式。
讨论MVVM,你还需要了解“数据绑定机制”,下文中我们详细说明。
MVC中的Model,被定义为完全独立于UI的数据或业务逻辑。模型常常用代码编写或者使用关系表/XML这样的纯数据表示。
MVC中的View,由按钮,窗口,图标和其它复杂的GUI控件这些可见的元素组成。View约定了一些快捷操作接口,它们接受MVC中Controller所需要管理的输入设备传递的信息,并使视图本身做出相应的响应。(研究当代GUI开发中Controller中发生的种种就有些严重跑题了……我更倾向于把它当做一个背景话题。我们没必要像在1979年时那样去探讨它)视图常常通过一些工具以“描述”的方式定义。介于这些工具和描述式语言的特性,MVC在View类中存储的视图状态信息将极难展示。举例来说,一个UI视图可能有不同模式的交互方式,比如“视图模式”和“编辑模式”(可以改变控件行为,改变可见元素样式),但这些模式信息常常是无法在XAML中进行描述的(虽然触发器是个不错的开始)。我们马上来解决这个问题。
我们该谈到数据绑定了。举一个简单的例子,视图和模型进行直接的绑定。一部分只供展示的模型字段进行单项绑定,另一部分可以被修改的模型字段进行双向绑定。举例来说,一个模型中bool值可以转化成字符绑定到一个TextBox(单向),也可以直接绑定到一个CheckBox(双向)。
然而通常,只有很小部门的UI元素可以直接和数据模型进行绑定,尤其在模型是开发者无法掌控的已经定义好的类或数据模板的时候,模型常常会存在一些无法直接和控件进行映射的的数据类型。UI的某些复杂操作是必须通过代码实现的,而这些代码,难以被视图所“理解”(即放到视图中不合适),但放到模型中又太特别了(或者这些逻辑没有被已存在的模型类所包含)。所以,我们需要一个存放诸如选择状态,模式信息的地方。
ViewModel就是为了完成这些任务而存在的。它意为“视图的模型”,提供模型与视图进行数据绑定的特殊支持,当然,比起模型,它更像视图。针对ViewModel提供否认数据绑定支持,它将包括将模型类型转化为视图类型的数据转化功能,以及操作那些可以被模型影响的视图。
我会在以后的文章中深入讨论如上观点,尤其说明怎样在ViewModel中实现命令绑定。但快速阐明这个模式,我们还是看一看下面的例子吧!
上面的图片展示了Sparkle(一款WebUI搭建工具)UI界面中的三个编辑面板。每一个面板都是使用MVVM模式开发的。最简单的是位于顶部的Library面板。它的模型是一个Assembly的列表(即每项都是System.Reflection.Assembly的一个实例),Assembly中的每一个列表又分别和一个控件列表建立关联。该视图由一个面板控件,一组控件样式和一个数据模板组成,该数据模板由一个展示Assembly列表的ComboBox(下拉选框)和一个可以展示控件列表的ListBox组成。我们把ComboBox的标题和Assembly的标题直接关联,而ListBox的中的每个项目,它们的名字即为它们所代表的控件的名称。ViewModel保存当前选择的Assembly,并执行了将相关控件进行展示的命令。选择是视图模型最常见的功能之一。但当我们将选择功能封装在控件当中,你会想问“为什么不将选择功能放在存放在视图(控件的父视图)当中呢?”这是因为视图中的多个控件的选择功能是有协作逻辑的。比起在视图中处理所有不同控件的协作关系,讲一个控件的选择展示控制和ViewModel进行绑定显然是更简单的方式(然后控件的选择协作逻辑在VM中处理)。基于如上设计,在Library面板中,(VM中)选择的Assembly同时决定了ComboBox和ListBox的展示内容。而且,设计者可以在不拷贝选择协作逻辑代码的情况下,轻松地修改原来的视图设计,比如使用ListBox来展示Assembly列表,用ComboBox来展示控件列表。
Appearance面板的模型中保存了在Sparkle的编辑区域中选中的形状或控件。视图上,我们看到一个展示我们选择的属性(一般是关于画笔或刷子的)的ListBox。那些按钮决定了我们的刷子或画笔是纯色的或渐变色的。色谱视图则用来编辑颜色组成。VM中保存的信息包括“被选择的属性”,“渐变色的边缘色信息”,“将颜色转换成文本描述或色谱图上坐标信息的数据转化方法”,“当画笔,刷子样式改变时发出的控制命令”。这个场景中,我们直接使用了Avalon框架提供的模型,视图可以轻易地完成巨大的变化,而VM则从UI的重用部分中提取展示的抽象。
最后一个例子是Project面板。这边的模型是属于一个MSBuild工程……而且,一个模型类是已经存在的。视图是一个树形控件,可以滚动,而且包含了详情菜单。ViewModel兼容了MSBuild的不考虑Avalon框架概念的设计模式(即通过命令行即可进行完美的工作)的问题,这样我们就可以对它们进行数据绑定,然后添加选项和命令了。
一旦你使用了MVVM模式,任何UI的问题都可以被快速处理。事实上,整个Sparkle的UI都是通过这种模式实现的。“在编辑区域选择形状或控件” 的展示面板的模型,其本身也是我们场景编辑器的一个ViewModel。Sparkle中面板的布局中,包含一个所有注册的面板的列表模型,一个由栅格为基础包含能定位视图的分割线的视图,还有一个VM,它保存了当前可见的面板和他们所应处的逻辑区域(比如编辑面板,右边,左边,底部)
今天就这样了……