謝偉
摘 要:MVVM即Model-View –ViewModel,是微軟WPF和Silverlight應(yīng)用特有的一種界面設(shè)計(jì)模式。使用MVVM設(shè)計(jì)模式可以幫助我們分離業(yè)務(wù)邏輯,顯示邏輯和用戶界面,使得我們的程序代碼結(jié)構(gòu)清晰,容易被閱讀、測(cè)試、維護(hù)、替換、擴(kuò)展和改進(jìn)。
關(guān)鍵詞: MVVM;設(shè)計(jì)模式;分層;用戶界面
一、什么是MVVM模式
MVVM是Model-View-ViewModel的簡(jiǎn)寫(xiě)。微軟的WPF帶來(lái)了新的技術(shù)體驗(yàn),如Silverlight、音頻、視頻、3D、動(dòng)畫(huà)……。這導(dǎo)致了軟件UI層更加細(xì)節(jié)化、可定制化。同時(shí),在技術(shù)層面,WPF也帶來(lái)了諸如Binding、Dependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性。MVVM(Model-View-ViewModel)框架的由來(lái)便是MVP(Model-View-Presenter)模式與WPF結(jié)合的應(yīng)用方式時(shí)發(fā)展演變過(guò)來(lái)的一種新型架構(gòu)框架。它立足于原有MVP框架并且把WPF的新特性揉合進(jìn)去,以應(yīng)對(duì)客戶日益復(fù)雜的需求變化。
二、為什么要有MVVM模式
開(kāi)發(fā)UI,對(duì)一個(gè)專業(yè)軟件并不容易。它需要未知數(shù)據(jù)、交互式設(shè)計(jì),可視化設(shè)計(jì)、聯(lián)通性,多線程、國(guó)際化、驗(yàn)證、單元測(cè)試以及其他的一些東西才能完成??紤]到UI要展示開(kāi)發(fā)的系統(tǒng)并且必須滿足用戶對(duì)系統(tǒng)風(fēng)格不可預(yù)知的變更,因此它是很多應(yīng)用程序最脆弱的地方。
有很多的設(shè)計(jì)模式可以幫助解決UI不斷變更這頭難纏的野獸,但是恰當(dāng)?shù)姆蛛x和描述多個(gè)關(guān)注點(diǎn)可能很困難。模式越復(fù)雜,之后用到的捷徑越可能破壞之前正確的努力。
自從人們開(kāi)始構(gòu)建UI時(shí),就有很多流行的設(shè)計(jì)模式讓UI構(gòu)建更容易。比如,MVP模式在各種UI編程平臺(tái)中都非常流行。MVP是MVC模式的一種變體,MVC模式已經(jīng)流行了幾十年了。MVVM比MVP更加簡(jiǎn)單,更不用說(shuō)MVC了。MVVM是在MVP之后出現(xiàn)的一種“更好的”UI模式解決方案。
如圖1,展現(xiàn)了MVVM是如何做到井然有序的。
圖1 ?MVVM模式圖解
(1)View中很多控件的數(shù)據(jù)類型和Model中的屬性不相同,例如開(kāi)發(fā)中,性別這種,Model中很可能就放置一個(gè)bool類型的變量。但是在前臺(tái)的展現(xiàn)View中,用戶看到的應(yīng)該是“男”和“女”。這就需要一種轉(zhuǎn)化。
(2)在WPF開(kāi)發(fā)中事件和命令同樣都可以讓一個(gè)UI正常的工作。我們知道Winform是事件驅(qū)動(dòng)的。所以理所當(dāng)然使用事件更容易理解和實(shí)現(xiàn)。但是帶來(lái)的問(wèn)題是后期的龐大與多種多樣的事件。
這兩種問(wèn)題很大的催生出Model和View中間的一個(gè)輔助角色ViewModel。它需要幫助View轉(zhuǎn)化相應(yīng)的數(shù)據(jù)給Model或者從Model處轉(zhuǎn)化成View可以顯示的內(nèi)容。同時(shí)它也需要將View的多種命令綁定給Model中的處理方法上。這些命令可以復(fù)用,當(dāng)其他View需要的時(shí)候,同樣可以調(diào)用命令中綁定的方法。ViewModel可以看成一個(gè)變種的Controller。
三、實(shí)現(xiàn)原理
解決了上一節(jié)提出的兩個(gè)問(wèn)題,實(shí)際上就解決了ViewModel的全部工作原理。
首先,從Binding問(wèn)題入手。在View中的控件存在一個(gè)屬性,叫做“DataContext”。這個(gè)是控件數(shù)據(jù)使用的源頭。DataContext屬性會(huì)給控件指定一個(gè)后臺(tái)模型,使得該控件使用的數(shù)據(jù)都是來(lái)自于這個(gè)模型類。所以,ViewModel應(yīng)該充當(dāng)這個(gè)后臺(tái)模型的作用,給View的控件提供顯示數(shù)據(jù)。同時(shí),ViewModel的數(shù)據(jù)應(yīng)該是來(lái)自于背后的Model所提供的。所以,簡(jiǎn)要的說(shuō),根據(jù)View中顯示的數(shù)據(jù)是何種Model,來(lái)定義ViewModel。舉個(gè)例子,如果View構(gòu)造了一個(gè)TextBlock控件,想要顯示的僅僅是Model中的一個(gè)string。那么在ViewModel中,應(yīng)該引用這里的Model,這樣作為View部分,就可以調(diào)用這個(gè)Model的某個(gè)string屬性了。
其次,解決Command問(wèn)題。WPF中已經(jīng)構(gòu)建了實(shí)現(xiàn)了ICommand的類RoutedCommand和RoutedUICommand。針對(duì)于不同的View事件,單獨(dú)使用哪一種都不是全權(quán)之策。因此,需要定義一個(gè)實(shí)現(xiàn)了ICommand接口的類。目前網(wǎng)上有現(xiàn)成的DelegateCommand和RelayCommand兩種解決方法。他們的共同點(diǎn)都是實(shí)現(xiàn)了ICommand接口,同時(shí)對(duì)于不同的事件,都可以綁定Model不同的處理方法。其區(qū)別是:i)DelegateCommand使用了一個(gè)RaiseCanExecuteChanged方法,需要開(kāi)發(fā)者手動(dòng)來(lái)觸發(fā)控件可執(zhí)行判斷。而RelayCommand中對(duì)于此處的觸發(fā)判斷是代理給CommandManager自己判斷了。更加方便;ii)DelegateCommand因?yàn)槭情_(kāi)發(fā)者手動(dòng)控制的,所以資源占用低,而RelayCommand在各種命令觸發(fā)的時(shí)候都需要判斷一下。所以資源占用也相對(duì)較高。這一點(diǎn)尤為能體現(xiàn)在復(fù)雜的系統(tǒng)中。所以使用哪一個(gè)都是看開(kāi)發(fā)人員自己選擇。當(dāng)然也可以自己手動(dòng)寫(xiě)一些更加適合自己的XXXCommand。其實(shí)現(xiàn)原理就是實(shí)現(xiàn)了ICommand接口。另外,使用委托的方法,將無(wú)返回值的Execute使用Action委托,有返回值的CanExecute使用Func委托。
參考文獻(xiàn):
[1]陳明、李猛坤、張強(qiáng).一種基于擴(kuò)展MVVM模式的SaaS面向服務(wù)計(jì)算模型[J].微電子學(xué)與計(jì)算機(jī),2010年08期
[2]李猛坤、陳明.一種基于擴(kuò)展MVVM模式的面向服務(wù)軟構(gòu)件模型[J].科學(xué)技術(shù)與工程,2011年10期