WPF MVVM應(yīng)用方式解析
WPF開發(fā)工具中有各種各樣的模式,運用這些不同的模式可以為我們創(chuàng)造各種不同的基于圖像處理的功能需求。其中,WPF MVVM是專為WPF打造的模式,也可以說MVVM僅僅是MVC的一個變種,但無論如何,就實踐而言,如果你或你的團隊沒有使用"Binding"的習慣,那么研究MVVM就沒有多大意義。#t#
另外,個人覺得,使用Command以及打造一種合理的簡化的方式去使用Command也與使用Binding一樣重要。
為了解決現(xiàn)實世界中的問題,我們需要將現(xiàn)實世界中的事物加以抽象,然后得到了Domain Object,無論貧血的還是富血的,我們都可以簡單地把他們歸結(jié)為"由現(xiàn)實世界抽象出來的模型",也就是我們的model,也就M-V-VM中的"M"。
但其無法與我們的用戶進行交互,所以,我們需要為其創(chuàng)建一個界面(視圖,View),該視圖可以與用戶輸入設(shè)備進行交互,這很棒,但問題是如何將View與我們的model關(guān)聯(lián)起來? Binding便可以發(fā)揮作用了,比如視圖上的某一個文本框中的文本和Model中的"用戶名"關(guān)聯(lián)起來,用戶便可以通過操作該文本框來訪問和修改Model的"用戶名"了。
這是極其簡單的情況,但實際編程時我們發(fā)現(xiàn),Model中的屬性(與方法)往往不那么容易與View中的界面控件關(guān)聯(lián)起來,比如,"類型不匹配": 界面控件所需要的類型與模型中屬性提高的類型不匹配。 "需要額外操作": 模型中的數(shù)據(jù)需要經(jīng)過一些額外的處理才能傳給視圖,反之亦然。 此時,我們意識到View似乎需要一個"Helper"類來處理一些額外工作。
這個helper所包含的代碼可以放在除了Model外的很多地方(我們現(xiàn)在不考慮貧血富血之類的爭論),比如View中,記得自己剛學習窗體程序開發(fā)時就是這么干的,將絕大多數(shù)處理邏輯放在那個所謂的CodeBehind中。
后來,正如大家在各種設(shè)計模式書籍中所看到的一樣,為了將View和Model剝離開來,實現(xiàn)view可替換(比如你可以講自己精心設(shè)計的軟件同時運行于窗體程序,Web甚至Mobile上),便有了MVC。 有了MVC以后似乎就開始滋生M-V-XXX之類的爭論與變種模型,比如MVP以及這里的WPF MVVM,甚至MVP也有著Supervising Controller與Presentation Model兩種方式。
但主要圍繞兩個問題,一是model與view之間的關(guān)系,完全隔離的?單向的還是雙向的? 二是這個"XXX"需要完成哪些功能,簡單流程調(diào)度?復(fù)雜規(guī)則處理? OK,這些爭論都沒有關(guān)系,是否采用某種模式取決于你的開發(fā)所處的環(huán)境(比如語言特性,框架特性)以及你的業(yè)務(wù)特性以及所面臨的主要變化點等等。
但與MVC,MVP所不同的是,WPF MVVM的引入不僅僅是技術(shù)上的原因(解除耦合應(yīng)對變化等老生常談),另外一個很大原因是:軟件團隊開發(fā)方式的改變。如果你做過一段時間的WPF項目開發(fā)的話,你可能會有比較明顯的感覺:在View層打造上,如何分配程序員和美工的工作。
以前我們團隊采用的便是"集成模式",我便兼職了其中的"Integrator"角色。這還不錯。但說實在的,這僅僅是一個在特殊情況下不得已而為之的暫時方案,所以我們付出了很大的努力開始轉(zhuǎn)向"收割模式"了,要轉(zhuǎn)向這個模式,至少需要兩個基本條件:
(1)你擁有能夠熟練運用Blend等工具能為程序員輸出XAML的美工,他專注于純粹的UI/UE,另外他還必須具有一定的"程序員"思維。以便輸出的東西能很好地作為程序的一部分而運轉(zhuǎn)起來,而不是僅僅"看上去"是那樣的。
(2)你需要能夠脫離View層但仍能編寫出高質(zhì)量代碼的程序員。
幸運的是,我們在努力創(chuàng)造條件1,并取得了很好的效果。(你可以招一個具有Flash腳本編寫經(jīng)驗的并且有極大的學習熱情的美工人員,并對他進行Blend的相關(guān)培訓)。 而WPF MVVM模式為我們實現(xiàn)第二個條件提供了極大的便利。 為什么MVC/MVP模式不行而MVVM可以呢? 很簡單,在MVC和MVP模式中,View層都具有很多代碼邏輯,開發(fā)View層的是程序員,雖然UI/UE團隊會做很多工作,但這個層的"實現(xiàn)者"仍然是程序員。
在以前的開發(fā)中,其工作得很好,而在WPF開發(fā)中程序員對View層的展現(xiàn)顯得力不從心了,美工(指符合上面條件1的美工)雖然很擅長,但他會說"可惜我不會程序"。于是,我們需要一種方式將View層的代碼邏輯抽取出來,并View層很純粹以便完全讓美工去打造它。相應(yīng)地,需要將View層的相應(yīng)邏輯抽取到一個代碼層上,以便讓程序員專注在這里。
回想一下,我們只所以要在View(Xaml)背后寫一些代碼(C#),無非是想傳遞一些數(shù)據(jù)以及傳遞數(shù)據(jù)時的數(shù)據(jù)的處理或在用戶與界面控件進行交互時執(zhí)行一些操作,最簡單的例子是在MVC中當界面發(fā)生交互時View去調(diào)用Controler中的某個方法,以便將該操作的相應(yīng)"指示"傳遞到"后臺"去。 在以前的技術(shù)中,這樣的"銜接性"的代碼是必須的。
而在WPF中,則可以通過另外的技術(shù)來進行層與層之間的"銜接",這就是"Binding" 和"Command",以及稍后我們會提到的"AttachBehavior"。 通過Binding,我們可以實現(xiàn)數(shù)據(jù)的傳遞; 通過Command,我們可以實現(xiàn)操作的調(diào)用。(AttachBehavior的作用稍后再談)。 Binding和Command是可以寫在XAML中的,這樣看來XAML后面對于的CS文件可以被完全拋棄或不予理會了。 這樣的XAML文件正是美工所需要的。
而這些對于Binding以及Command的定義描述以及其他相關(guān)信息的代碼應(yīng)該放在那里呢,當然不是View,更不是Model,是"ViewModel"。 ViewModel是為這個View所量身定制的,它包含了Binding是所需的相關(guān)信息,比如Converter以及為View的Binding提供DataContext,它包含了Command的定義以便View層可以直接使用,另外,它還是一個變種的Controler,它得負責業(yè)務(wù)流程的調(diào)度。
于是,正如"時勢造英雄"所言,WPF MVVM就誕生了。