原文背景
相對于 MVC 的歷史來說,MVVM 是一個(gè)相當(dāng)新的架構(gòu),MVVM 最早于 2005 年被微軟的 WPF 和 Silverlight 的架構(gòu)師 John Gossman 提出,并且應(yīng)用在微軟的軟件開發(fā)中。該篇譯文的原文即為John Gossman當(dāng)年發(fā)布的博文。
翻譯這篇文章,是期望在當(dāng)今普遍地對MVX(該文主要說MVVM)相關(guān)模式片面理解的大環(huán)境下,讓大家可以基于MVX最初提出,對我們對與MVX的實(shí)踐應(yīng)用以及MVX的本源思路進(jìn)行一些思考。
文章關(guān)鍵技術(shù)名詞簡析
WPF :Windows Presentation Foundation,是微軟推出的基于Windows 的用戶界面框架,屬于.NET Framework 3.0的一部分。
MVC :Model/View/Controller,模型/視圖/控制器開發(fā)模式。
MVVM : Model/View/ViewModel,模型/視圖/視圖模型開發(fā)模式,是MVC的一個(gè)變種模式。
HTML :HyperText Markup Language,超文本標(biāo)記語言,我們查看的網(wǎng)頁的基礎(chǔ)語言就是它。
XAML :eXtensible Application Markup Language,可擴(kuò)展應(yīng)用程序標(biāo)記語言,是微軟公司為構(gòu)建應(yīng)用程序用戶界面而創(chuàng)建的一種新的描述性語言。
WYSIWYG :What You See Is What You Got,所見即所得,比如你在用美圖秀秀處理圖片的時(shí)候,圖片處理完成展示的樣子就是它最終的樣子。(而不像用代碼寫視圖一樣,從代碼中,外行人完全不知道最終展示的視圖的樣子)。
Dreamweaver :一款“所見即所得”的網(wǎng)頁編輯器。
Flash : 一款“所見即所得”的動畫編輯器。
Sparkle :另一款“所見即所得”的網(wǎng)頁設(shè)計(jì)工具。
Smalltalk :公認(rèn)的歷史上第二個(gè)面向?qū)ο蟮某绦蛟O(shè)計(jì)語言(第一個(gè)是Simula 67)和第一個(gè)真正的集成開發(fā)環(huán)境 (IDE)。
Avalon :一個(gè)簡單迷你的MVVM框架。
關(guān)系表 :原文中是relational tables,個(gè)人感覺理解為關(guān)系型數(shù)據(jù)庫的數(shù)據(jù)表就沒什么大問題了。
XML :eXtensible Markup Language,可擴(kuò)展標(biāo)記語言,經(jīng)常用來描述進(jìn)行通信的數(shù)據(jù)結(jié)構(gòu)。(類似Json)
GUI :Graphical User Interface,圖形用戶界面。
觸發(fā)器 :trigger,SQL server 提供給程序員和數(shù)據(jù)分析員來保證數(shù)據(jù)完整性的一種方法,它是與表事件相關(guān)的特殊的存儲過程。它的執(zhí)行不是由程序調(diào)用,也不是手工啟動,而是由事件來觸發(fā)。
單向綁定 :基于本文,是模型和視圖的綁定,可以理解為模型數(shù)據(jù)變化觸發(fā)視圖更新。
雙向綁定 :基于本文,是模型和視圖的綁定,可以理解為模型數(shù)據(jù)變化觸發(fā)視圖更新,且視圖操作觸發(fā)模型數(shù)據(jù)更新。
bool :一個(gè)數(shù)據(jù)類型,其取值只能為0或1。
TextBox :文本框(翻譯不需要太糾結(jié))。
CheckBox,選擇框,就是那個(gè)你在注冊賬號時(shí)候,注冊協(xié)議旁邊可以點(diǎn)擊打鉤的那種控件。(如圖)

UI,User Interface,用戶界面。
Assembly :.Net中反射機(jī)制的一個(gè)類封裝。相關(guān)的數(shù)據(jù)結(jié)構(gòu)有如下幾個(gè):AppDomain(應(yīng)用程序域),Assembly(程序集類),Module(模塊類),Type(使用反射得到的類型信息的最核心類)。它們之間的關(guān)系是:AppDomain包含多個(gè)Assembly,Assembly包含多個(gè)Module,Module包含多個(gè)Type。Assembly是有一個(gè)name屬性的,該文中,舉例的工程直接使用了Assembly數(shù)據(jù)結(jié)構(gòu)。
ComboBox :下拉選框,點(diǎn)擊了下拉框會彈出選擇菜單的那種。(如圖)

ListBox :列表,本文中的話,還是能滾的那種。(如圖)

Library/Appearance/Project :文中直接對應(yīng)舉出的例子對應(yīng)的三個(gè)面板,無需特別翻譯。
MSBuild :Microsoft Build Engine 的縮寫,基于該文,MSBuild Project的模型理解為一個(gè)已存在的,且不方便修改其屬性定義的模型就夠了。
譯文正文
使用MVVM模式搭建WPF應(yīng)用的方法介紹
MVVM是MVC模式的一個(gè)演變,針對一個(gè)視圖的展示樣式,比起傳統(tǒng)的開發(fā)者,現(xiàn)在往往是設(shè)計(jì)師更為關(guān)注,MVVM正是為這種狀況而定制的一種模式。一個(gè)設(shè)計(jì)師,往往更關(guān)注圖形、藝術(shù)的呈現(xiàn)效果(傳統(tǒng)的開發(fā)者則不會),他們常常使用聲明式語言(如HTML,XAML)和WYSIWYG工具(所見即所得編輯器,如Dreamweaver,F(xiàn)lash,Sparkle)。簡單地說,不同于后端邏輯或者后臺數(shù)據(jù),一個(gè)應(yīng)用的UI部分常常會被不同的人使用各種各樣的開發(fā)工具,各種各樣的開發(fā)語言來完成開發(fā)。從MVC到MVVM促使了從Smalltalk到Web/Avalon這樣一個(gè)轉(zhuǎn)變,前者(smalltalk)只使用一種語言一套環(huán)境來開發(fā)一款應(yīng)用,后者則為我們更為熟知的現(xiàn)代開發(fā)模式。
討論MVVM,你還需要了解“數(shù)據(jù)綁定機(jī)制”,下文中我們詳細(xì)說明。
MVC中的Model,被定義為完全獨(dú)立于UI的數(shù)據(jù)或業(yè)務(wù)邏輯。模型常常用代碼編寫或者使用關(guān)系表/XML這樣的純數(shù)據(jù)表示。
MVC中的View,由按鈕,窗口,圖標(biāo)和其它復(fù)雜的GUI控件這些可見的元素組成。View約定了一些快捷操作接口,它們接受MVC中Controller所需要管理的輸入設(shè)備傳遞的信息,并使視圖本身做出相應(yīng)的響應(yīng)。(研究當(dāng)代GUI開發(fā)中Controller中發(fā)生的種種就有些嚴(yán)重跑題了……我更傾向于把它當(dāng)做一個(gè)背景話題。我們沒必要像在1979年時(shí)那樣去探討它)視圖常常通過一些工具以“描述”的方式定義。介于這些工具和描述式語言的特性,MVC在View類中存儲的視圖狀態(tài)信息將極難展示。舉例來說,一個(gè)UI視圖可能有不同模式的交互方式,比如“視圖模式”和“編輯模式”(可以改變控件行為,改變可見元素樣式),但這些模式信息常常是無法在XAML中進(jìn)行描述的(雖然觸發(fā)器是個(gè)不錯的開始)。我們馬上來解決這個(gè)問題。
我們該談到數(shù)據(jù)綁定了。舉一個(gè)簡單的例子,視圖和模型進(jìn)行直接的綁定。一部分只供展示的模型字段進(jìn)行單項(xiàng)綁定,另一部分可以被修改的模型字段進(jìn)行雙向綁定。舉例來說,一個(gè)模型中bool值可以轉(zhuǎn)化成字符綁定到一個(gè)TextBox(單向),也可以直接綁定到一個(gè)CheckBox(雙向)。
然而通常,只有很小部門的UI元素可以直接和數(shù)據(jù)模型進(jìn)行綁定,尤其在模型是開發(fā)者無法掌控的已經(jīng)定義好的類或數(shù)據(jù)模板的時(shí)候,模型常常會存在一些無法直接和控件進(jìn)行映射的的數(shù)據(jù)類型。UI的某些復(fù)雜操作是必須通過代碼實(shí)現(xiàn)的,而這些代碼,難以被視圖所“理解”(即放到視圖中不合適),但放到模型中又太特別了(或者這些邏輯沒有被已存在的模型類所包含)。所以,我們需要一個(gè)存放諸如選擇狀態(tài),模式信息的地方。
ViewModel就是為了完成這些任務(wù)而存在的。它意為“視圖的模型”,提供模型與視圖進(jìn)行數(shù)據(jù)綁定的特殊支持,當(dāng)然,比起模型,它更像視圖。針對ViewModel提供否認(rèn)數(shù)據(jù)綁定支持,它將包括將模型類型轉(zhuǎn)化為視圖類型的數(shù)據(jù)轉(zhuǎn)化功能,以及操作那些可以被模型影響的視圖。
我會在以后的文章中深入討論如上觀點(diǎn),尤其說明怎樣在ViewModel中實(shí)現(xiàn)命令綁定。但快速闡明這個(gè)模式,我們還是看一看下面的例子吧!

上面的圖片展示了Sparkle(一款WebUI搭建工具)UI界面中的三個(gè)編輯面板。每一個(gè)面板都是使用MVVM模式開發(fā)的。最簡單的是位于頂部的Library面板。它的模型是一個(gè)Assembly的列表(即每項(xiàng)都是System.Reflection.Assembly的一個(gè)實(shí)例),Assembly中的每一個(gè)列表又分別和一個(gè)控件列表建立關(guān)聯(lián)。該視圖由一個(gè)面板控件,一組控件樣式和一個(gè)數(shù)據(jù)模板組成,該數(shù)據(jù)模板由一個(gè)展示Assembly列表的ComboBox(下拉選框)和一個(gè)可以展示控件列表的ListBox組成。我們把ComboBox的標(biāo)題和Assembly的標(biāo)題直接關(guān)聯(lián),而ListBox的中的每個(gè)項(xiàng)目,它們的名字即為它們所代表的控件的名稱。ViewModel保存當(dāng)前選擇的Assembly,并執(zhí)行了將相關(guān)控件進(jìn)行展示的命令。選擇是視圖模型最常見的功能之一。但當(dāng)我們將選擇功能封裝在控件當(dāng)中,你會想問“為什么不將選擇功能放在存放在視圖(控件的父視圖)當(dāng)中呢?”這是因?yàn)橐晥D中的多個(gè)控件的選擇功能是有協(xié)作邏輯的。比起在視圖中處理所有不同控件的協(xié)作關(guān)系,講一個(gè)控件的選擇展示控制和ViewModel進(jìn)行綁定顯然是更簡單的方式(然后控件的選擇協(xié)作邏輯在VM中處理)?;谌缟显O(shè)計(jì),在Library面板中,(VM中)選擇的Assembly同時(shí)決定了ComboBox和ListBox的展示內(nèi)容。而且,設(shè)計(jì)者可以在不拷貝選擇協(xié)作邏輯代碼的情況下,輕松地修改原來的視圖設(shè)計(jì),比如使用ListBox來展示Assembly列表,用ComboBox來展示控件列表。
Appearance面板的模型中保存了在Sparkle的編輯區(qū)域中選中的形狀或控件。視圖上,我們看到一個(gè)展示我們選擇的屬性(一般是關(guān)于畫筆或刷子的)的ListBox。那些按鈕決定了我們的刷子或畫筆是純色的或漸變色的。色譜視圖則用來編輯顏色組成。VM中保存的信息包括“被選擇的屬性”,“漸變色的邊緣色信息”,“將顏色轉(zhuǎn)換成文本描述或色譜圖上坐標(biāo)信息的數(shù)據(jù)轉(zhuǎn)化方法”,“當(dāng)畫筆,刷子樣式改變時(shí)發(fā)出的控制命令”。這個(gè)場景中,我們直接使用了Avalon框架提供的模型,視圖可以輕易地完成巨大的變化,而VM則從UI的重用部分中提取展示的抽象。
最后一個(gè)例子是Project面板。這邊的模型是屬于一個(gè)MSBuild工程……而且,一個(gè)模型類是已經(jīng)存在的。視圖是一個(gè)樹形控件,可以滾動,而且包含了詳情菜單。ViewModel兼容了MSBuild的不考慮Avalon框架概念的設(shè)計(jì)模式(即通過命令行即可進(jìn)行完美的工作)的問題,這樣我們就可以對它們進(jìn)行數(shù)據(jù)綁定,然后添加選項(xiàng)和命令了。
一旦你使用了MVVM模式,任何UI的問題都可以被快速處理。事實(shí)上,整個(gè)Sparkle的UI都是通過這種模式實(shí)現(xiàn)的。“在編輯區(qū)域選擇形狀或控件” 的展示面板的模型,其本身也是我們場景編輯器的一個(gè)ViewModel。Sparkle中面板的布局中,包含一個(gè)所有注冊的面板的列表模型,一個(gè)由柵格為基礎(chǔ)包含能定位視圖的分割線的視圖,還有一個(gè)VM,它保存了當(dāng)前可見的面板和他們所應(yīng)處的邏輯區(qū)域(比如編輯面板,右邊,左邊,底部)
今天就這樣了……