Prism 4 文檔 ---第7章 組成用戶界面

     一個應用程序的用戶界面(UI)能夠通用如下幾種模式之一來構建:html

窗體所須要全部的控件都包含在一個單獨的XAML文件中,在設計時組合這個窗體。web

窗體的邏輯區域被分割到單獨的部分中,一般指喲過戶控件。這些部分被窗體引用而且在設計時組合窗體。shell

窗體的邏輯區域被分割到單獨的部分中,一般指喲過戶控件。這些部分是不被窗體所知道的,而且在運行時動態的將它們添加到窗體中。使用這種方法的應用程序稱爲複合應用程序。數據庫

    一個複合應用程序的UI是從被認爲是一般包含在程序模塊中的View的可視化組件鬆耦合的組合起來的,可是它們不須要是。若是你將應用程序切分紅模塊,你須要某種方式來鬆散的組合UI,可是你可能甚至在View不在模塊中時也選擇使用這種方式。爲了用戶,該應用程序提供了一個無縫的用戶體驗,並提供了一個徹底集成的應用程序。express

    爲了組合你的UI,你須要一個容許你建立一個能鬆散耦合在運行時建立可視化元素的架構。另外,這個架構應該體統這些元素以一種鬆散耦合方式通訊的策略。編程

    Stock Trader RI 就是經過加載多個來自不一樣模塊中的經過Shell暴露給Region的View來組合起來的,以下圖所示。windows

clipboard

UI佈局概念設計模式

    在一個組合應用程序中的根對象被認爲是Shell。Shell在應用程序中扮演這一個母版頁的角色。Shell包含了一個或者多個區域。區域是在運行時會被加載的內容的佔位符。區域被附加到UI元素上,例如內容空,列表項控件,Tab控件或者一個自定義控件而且管理UI元素的內容。區域的內容能夠被自動的加載或者按須要加載,這取決於應用程序的需求。性能優化

    一般,一個區域的內容是一個View。一個View封裝了UI的你想要儘量與程序的其餘部分保持鬆耦合關係的一部分,你能夠將一個View定義成一個用戶控件,數據模板,捉着甚至是一個自定義控件。網絡

    一個區域管理着View的顯示和佈局。區域能夠經過它們的名稱以一種鬆耦合的方式被訪問而且支持動態的添加和移除Views,一個區域附加的一個宿主控件,將區域想象成一個動態加載View的容器。

    接下來的幾節將會介紹複合應用程序開發中的高級核心概念。

Shell

    shell是應用程序中一個包含着主要UI內容的跟對象。在WPF應用程序中,shell是一個Window對象,在Silverlight程序中,shell是RootVisualUserControl

    shell扮演着提供應用程序佈局結構的母版頁的角色。shell包含着一個或者多個命名的區域,這些區域能夠指定將會顯示的View。它也能夠定義具體的頂級的UI元素,例如背景,主菜單和工具條。

    shell訂閱了應用程序的總體外觀。它可能會定義在它的佈局中展示的可見的樣式和邊框。它也可能定義了將會應用到添加到shell中的View的樣式,模板和主題等。

    一般,shell是WPF應用程序項目的一部分或者Silverlight項目的主要內容。包含shell的程序集也許會也或許不會依賴包含着將會被加載到shell的區域內的Views的程序集。

Views

    View是複合應用程序中UI結構中主要的單元。你能夠將view定義成一個用戶控件,數據模板,或者一個自定義控件。一個View封裝了UI的你想要儘量與程序的其餘部分保持鬆耦合關係的一部分。你能夠選擇基於封裝或者一塊功能的View中發生的內容,或者你能夠選擇定義一些東西做爲一個view由於你將會在應用程序中產生這個View的多個示例。由於WPF和Silverlight的內容模型,Prism類庫定義一個view時不須要什麼指定的東西。最賤的訂閱一個view的方法就是定義成一個用戶控件。爲了往UI中添加一個view,你只須要一種方法去構造它並將它添加到容器中。WPF和Silverlight提供了實現這些內容的機制。Prism類庫添加了定義了能夠在運行時動態的添加到一個區域的能力。

組合Views

    支持特定功能的視圖可能會變得複雜。在這種狀況下,你可能要將View拆分紅幾個子View,並由父View處理利用子View來構建自身。應用程序可能在設計時靜態的配置這些,或者它可能支持在運行時經過一個包含的區域將子View添加到模塊中。當你有一個在某個類中未能完整的定義View的類時,你能夠選用一個組合View。在許多的狀況下,一個組合view扶着這構建子view及協調tam之間的交互。你能夠經過使用Prism類庫命令和事件聚合組合來定義與其餘子view以及它們的父view之間鬆耦合的子view。
Views和設計模式

    雖然Prism類庫並無要求你使用它們,可是,你在實現一個view時考慮使用一種UI設計模式。Stock Trader RI和QuickStarts演示了使用MVVM做爲實現一個View佈局和View邏輯之間清晰的分離的模式。

    推薦使用MVVM UI設計模式由於它原生的適應於XAML平臺,WPF,Silverlight,以及Silverlight for Windows Phone 7。系統的依賴屬性和平臺豐富的數據綁定支持使得View和ViewModel之間可以以一種鬆耦合分方式進行通訊。

    view和邏輯的分離對於可測試性與可維護性很是重要,它提高了開發與設計工做流的效率。

    你可使用一個用戶控件或者一個自定義控件而且將全部的邏輯卸載後臺代碼文件中來建立一個View,你的View將會很是難測試由於你必須在單元測試的邏輯中建立一個View的實例。這是一個問題,特別若是view源自,或依賴於運行的WPF或Silverlight組件做爲其執行上下文的一部分。爲了保證你能夠在單元測試中在一個不依賴這些的隔離的環境中測試view邏輯。你須要可以建立視圖的模擬,以消除執行上下文,這須要將view和邏輯拆分到單獨的類中。

    若是你將一個view做爲一個數據模板,這將會使得它自身沒有相關的代碼。所以,你須要將這些相關的邏輯放到其餘的地方。一樣佈局與邏輯清晰分離也是可測試性所須要的也有助於使view更易於維護。

    注意:

    單元測試和UI自動測試是兩種不一樣測試覆蓋的測試類型。

    單元測試的最佳實踐建議的對象單獨進行測試。爲了達到目的隔離,你須要一個樣機或存根每一個外部依賴。而後,單元測試顆粒能夠運行侵害測試對象。

    UI自動化測試運行該應用程序,適用於用戶界面的手勢,而後測試預期的結果。這種類型的測試驗證UI元素已正確鏈接到應用程序邏輯。

    view與邏輯的分離提供了關注點的清晰分離。另外對於可測試性的考慮,這種分離使得UI設計者與開發者相互獨立。更多的關於MVVM模式,請看第五章「實現MVVM模式」。

命令,UI觸發器,動做和行爲

    當在後臺文件中實現了view的邏輯,你能夠將UI交互服務添加到事件上。可是,當使用MVVM時,view model不能直接的處理UI引起的事件。爲了在viewmodel中路由處理這些事件動做,你可使用命令,UI觸發器,動做,以及行爲。

命令

    命令分開了調用從邏輯中執行命令的邏輯對象和語義。內建的命令代表了一個動做是否可用的能力。UI中的命令綁定到了ViewModel中的ICommand屬性。關於命令的更多信息。請看第5章「實現MVVM模式」中的「命令」一節。

UI觸發器,動做和行爲

    觸發器,動做和行爲是Microsoft.Expression.Interactivity 命名空間下的一部分而且同Expression Blend一塊兒發佈。而且它們也是Expression SDK的一部分。觸發器,動做和行爲提供了一個處理UI事件或者命令的全面的API,而且經過路由將它們綁定到DataContext暴露的ICommand屬性提供的方法。有關 UI觸發器,動做和行爲的更多信息,請看第5章「實現MVVM模式」中「從View調用命令對象」和「從View調用命令方法」這兩節。

數據綁定

    數據綁定是XAML平臺的框架中最重要的功能之一。爲了可以在XAML平臺上成功的開發應用程序。你須要對數據綁定有一個深入的理解。

    數據綁定擁有依賴屬性系統提供給的固有的屬性變化通知機制的所有有點。當結合了CLR中INotifyPropertyChanged接口的實現時,在數據綁定中變動通知能夠作到目標與源對象之間無代碼的交互。

    數據綁定經過使用一個值轉換從一個類型轉換到另外一個類型從而可使得不一樣目標和源類型之間的綁定。數據綁定在它的管道中保留有多重校驗的鉤子,你能夠在用戶輸入時進行數據驗證。

    強烈的鼓勵你去讀一讀MSDN上的"Dependency Properties Overview" and "Data Binding Overview"。這兩個主題的徹底理解對於在XAML平臺上開發應用程序是很是關鍵的。有關數據綁定的更多信息,請看第5章」實現MVVM模式「的」數據綁定「一節。

區域(Regions)

    在Prism類庫中區域貫穿着區域管理,區域,區域適配器,接下來的幾節將會介紹它們是如何在一塊兒工做的。

區域管理

    RegionManager類負責建立和維護承載控件的區域的集合。RegionManager使用了一個控件指定適配器來關聯區域和承載控件。下面的插圖顯示了由RegionManager類建立的區域,控件和適配器之間的關係。

clipboard[1]

RegionManager類可在代碼或者XAML中建立區域。RegionManager.RegionName附加屬性用來應用到承載控件的附加屬性中在XAML中建立區域。

    應用程序能夠包含一個或者多個RegionManager類的示例。你能夠指定你本身的區域要註冊到的RegionManager類的實例。這在你想要在可視化書中移動控件而且不想在附加屬性值被刪除後再次聲明區域時很是有用。

RegionManager類提供了一個RegionContext附加數據來使得區域之間共享數據。

區域實現

    區域是一個實現了IRegion接口的類。Region術語表明了一個能夠擁有在UI上呈現的動態數據的容器。區域使得Prism類庫在UI容器中經過預約義佔位符來的放置模塊中的動態內容。

    區域能夠承載任何類型的UI內容。模塊中包含的UI內容能夠呈現爲一個用戶控件,一個關聯了數據模板的數據類型,一個自定義控件,或者它們的組合。這使得你能夠定義UI區域的內容,而後將模塊中的內容放置到UI區域中。

    一個區域能夠包含零個或多個子項。這取決於區域管理的承載控件的類型,能夠顯示一個或者多個子項。例如,ContentControl控件只能展現一個對象,然而,加載的區域能夠包含多個子項,而且,ItemsControl能夠展現多個子項。容許每個都在UI中是可見的。

    在下面的插圖中,Stock Trader RI Shell包含了四個區域:MainRegion, MainToolbarRegion, ResearchRegion, 和ActionRegion.這些區域是被不一樣的模塊發佈的,而且這些內容能夠隨時被改變。

clipboard[2]

用戶控件模塊到區域映射

    爲了演示模塊和內容是如何跟區域關聯在一塊兒的,狀況下面的插圖,它展現了WatchModuleNewsModule 在Shell中對於區域的關聯關係。

MainRegion 包含了WatchModule中的 WatchListView 控件,ResearchRegion 包含了NewsModule中的 ArticleView 控件 。

    在基於Prism窗口的應用程序中,這樣的映射關係將會是設計過程的一部分,由於設計人員和開發人員使用它們來決定將內容呈現到指定的區域中。這使得設計人員來決定須要的所有空間以及確保在可用控件中展現額外項目的空間。

clipboard[3]

默認功能性區域

    當你須要徹底的理解區域實現來使用它們的時候,理解控件和區域之間是如何被關聯的以及默認區域的功能將會頗有用。例如,如何定位區域和實例化View,如何在View激活時被通知,或者view的生命週期被激活。

區域適配器

    爲了將UI控件暴露爲一個區域,它須要一個區域適配器。區域適配器扶着建立一個區域和關聯控件。這容許你使用IRegion接口經過統一的方式管理UI控件中的內容。每個區域適配器適配一個指定的UI控件。Prism類庫提供瞭如下三個區域適配器:

  • ContentControlRegionAdapter。這個適配器適配System.Windows.Controls.ContentControl控件及其派生控件。
  • SelectorRegionAdapter。這個適配器適配System.Windows.Controls.Primitives.Selector的派生控件,例如System.Windows.Controls.TabControl控件。
  • ItemsControlRegionAdapter。這個適配器適配System.Windows.Controls.ItemsControl控件及其派生控件。

    注意:

Silverlight版本的Prism中支持名爲TabControlRegionAdapter的第四個適配器,這是由於SilverLight中的TabControl控件沒有繼承Selector類,而且與WPF版本的控件行爲不相同。

區域行爲

    Prism類庫介紹了區域行爲的概念,這裏有一些區域的多數的功能性的可插拔的組件,區域行爲的引入被用來支持View發現以及區域上下文,並建立一個在WPF和Silverlight中一致的API。另外,行爲提供了一種擴展區域實現的高效的方式。

    區域行爲是一個附加到區域中使得區域擁有額外功能的類。這種行爲被附加到區域中而且在區域的生命週期中一直保持活動狀態。例如,當AutoPopulateRegionBehavior附加到一個區域,它將會自動實例化,而且添加添加任何以名稱註冊到區域中的ViewTypes。在區域的聲明週期中,它一直監視RegionViewRegistry用以新的註冊,添加或替換一個已存在的自定義的區域行爲是很是容易的,不管是在一個系統層面仍是一個單獨的基於區域的。

    接下來的幾節描述自動添加到全部區域中的默認行爲。惟一一個附加到派生自Selector的控件行爲是,SelectorItemsSourceSyncBehavior。

註冊行爲

RegionManagerRegistrationBehavior負責確保區域添加到正確的RegionManager中。當一個view或一個控件做爲另外一個控件或者區域的子項添加到可視樹中時,這個控件中定義的任何區域都應該被註冊到父控件的RegionManager中,當子控件被移除後,這些註冊的區域將會被卸載。

自動填充行爲

    有兩個類負責View發現功能的實現。一個是AutoPopulateRegionBehavior。當它被添加到一個區域時,它將會檢索區域名稱下全部註冊的view類型。而後,它建立這些view的實例並將他們添加到區域中。在區域被建立以後,AutoPopulateRegionBehavior監視RegionViewRegistry用以區域名稱中任何新註冊的view類型。

    若是你想要在view發現過程當中處理更過控件,考慮建立你本身的關於IRegionViewRegistryAutoPopulateRegionBehavior的實現。

區域上下文行爲

    區域上下文的功能被包含在兩個行爲中:SyncRegionContextWithHostBehavior BindRegionContextToDependencyObjectBehavior。這些行爲負責監視上下文的區域發生的變化以及經過附加到view的上下文依賴屬性來同步上下文信息。

激活行爲

RegionActiveAwareBehavior 負責當view在激活或者非激活時通知view,view必須實現IActiveAware接口來接受這些變化的通知。激活通知是單向的(它從行爲傳遞到view)。view不能經過改變IActiveAware接口的激活屬性來影響它的活動狀態。

區域生命週期行爲

RegionMemberLifetimeBehavior負責着決定某項當它再也不是活動的時候是否應該從區域中移除。RegionMemberLifetimeBehavior
指定控件的行爲監視着ActiveViews集合來發現那些轉變爲非活動狀態的項目。這個行爲檢查IRegionMemberLifetimeRegionMemberLifetimeAttribute(按該順序)移除的項目,已決定它是否應該在移除後保持生命週期。

如何集合中的項目System.Windows.FrameworkElement類型的對象,它也會檢查她的IRegionMemberLifetimeRegionMemberLifetimeAttribute.的DataContext屬性。

這些區域項按一下順序被檢查:

  1. IRegionMemberLifetime.KeepAlive
  2. DataContext's IRegionMemberLifetime.KeepAlive
  3. RegionMemberLifetimeAttribute.KeepAlive
  4. DataContext's RegionMemberLifetimeAttribute.KeepAlive

控件指定的行爲

    SelectorItemsSourceSyncBehavior只用於那些派生自Selector的控件,好比WPF中的Tab控件。他負責區域中的Views和選擇容器中項目之間的同步,而且負責區域中活動的Views和選中項之間的同步。

    TabControlRegionSyncBehavior只用於Silverlight,它爲Siliverlight中的Tab控件提供了與SelectorItemsSourceSyncBehavior相同的行爲。

擴展區域實現

    Prism類庫提供了容許你去自定義或者擴展API提供的默認行爲的擴展點。例如,你能夠開發你本身的區域適配器,區域行爲,改變API轉換URI導航的方式,或者在Silverlight Frame Navigation中擴展API的導航工做。關於擴展Prism類庫的擴展相關的內容,請看「擴展Prism」。

View 組合

    view 組合是view的構建工做。在一個組合應用程序中,來自多個模塊中中的views須要在運行時在應用程序UI中指定的地方展現。爲了達到這個目的,你須要定義這些view將會顯示的位置,以及這些view將會如何被建立及如何在這些位置展現。

    View能夠經過視圖發現自動的方式或經過view注入以編程的方式建立和在指定位置展現。這兩種技術肯定了Views如何單獨映射到該應用程序的用戶界面中指定的位置。

View 發現

    在視圖發現中,你在區域的名稱和view的類型之間創建RegionViewRegistry關係,當一個區域被建立時,這個區域將會查找與此區域相關聯的ViewTypes而且自動的實例化它們和加載相應的views。所以,在視圖發現過程當中,你沒必要顯示的控制,對應的View將會被加載以及展現。

View 注入

    在視圖注入中,你須要以編碼的方式得到一個區域的引用,而後經過程序的方式將view添加到區域中。一般,這些在一個模塊初始化時或者在做爲一個用戶動做的結果時進行。你將會在代碼中經過名稱查詢一個指定區域的RegionManager,而後將view注入到其中。在視圖注入中,你須要在views被加載和展現時更過的手動控制。你也擁有從區域中移除這些view的能力。然而,在視圖注入中,你不能將一個view添加到一個尚未被建立的區域中。

導航

    Prism 4.0的類庫中包含了導航相關的API。這些導航API經過使你用URI導航到一個區域的方式簡化了視圖注入的過程。這些導航API實例化了View,添加它到區域中,而後激活它。另外,這些導航API容許返回到區域中建立上一個view。關於導航API的更過信息,請看第8章"導航"

什麼時候使用View發現 VS View 注入

    爲區域選擇使用哪一種視圖加載策略取決於應用程序的需求以及區域的功能。

在如下狀況下使用視圖發現方式:

  • 指望或者要求自動的加載view
  • view的單例將會被加載到區域中。

在如下狀況下使用視圖注入的方式:

  • 你的應用程序使用了導航API
  • 你須要明確或者經過編程方式控制一個view在建立和展現的時候,或者你須要工一個區域中移除一個view;例如,做爲應用程序邏輯或者導航的結果。
  • 你須要展現一個區域中同一個view的多個實例,這些不一樣的實例綁定不一樣的數據。
  • 你須要控制將view添加到哪個區域實例中。例如,你想要將一個客戶詳細信息視圖添加到一個特定的客戶詳細區域。

UI佈局場景

    在組合應用程序中,來自多個模塊中的視圖在運行時在應用程序UI中指定的位置被展現。爲了達到這點,你須要定義這些視圖將會被展現的位置以及這些視圖將會如何被建立及在這些位置展現。

    視圖和UI中的的位置之間的解耦使得應用程序的界面和佈局發展爲在區域中顯示的獨立的視圖。

    接下來的幾描述了在你開發一個組合應用程序中將會遇到的核心場景。在適當的時候,Stock Trader RI系統的例子將會演示這種場景的解決方案。

實現Shell

    Shell 是應用程序的主界面中包含的根對象,在一個WPF程序中。Shell是一個Window對象。在一個Silverlight程序中,shell是一個RootVisualUserControl。

shell能夠包含已命名的區域,模塊能夠指定視圖顯示到這些區域中。它也能夠定義一個肯定的頂級的UI元素,例如主菜單和工具欄。shell定義了應用程序的整個框架和界面,這個ASP.NET的主頁面控件有些類似。它能夠定義在自身佈局中展現的樣式和邊框,而且,它也能夠定義添加到shell中的視圖能夠應用的樣式,模板,和主題等。

    你不需用使用一個不一樣的shell做爲應用程序界面的一部分來使用Prism類庫。若是你正在構建一個完整的組合應用程序,實現一個提供了良好定義的跟shell而且實現創建應用程序主UI的模式。然而,若是你在添加Prism類庫的功能到一個已存在的應用程序,你不要必須改變應用程序的基礎結構來添加一個shell。而是,你能夠修改已存在的窗口或者控件的定義來添加能夠引入視圖的區域。

    你也能夠在應用程序中存在不止一個應用shell。若是你將會=設計爲用戶打開多餘一個的頂級窗口的應用程序,每個頂級的窗口扮演着包含內容的shell。

Stock Trader RI Shell

WPF Stock Trader RI 使用一個shell做爲它的主窗口。在下面的插圖中,shell和視圖被高亮顯示。shell是WPF Stock Trader RI程序啓動時的主窗口,它包含了全部的視圖。它定義了模塊添加它們的視圖到的區域和一些列的頂級的UI項,包括CFI Stock Trader title 和 Watch List tear-off 標題。

clipboard[4]

    Stock Trader RI中的Shell.xaml,它的後置代碼文件Shell.xaml.cs和它的視圖墨香ShellViewModel.cs提供了shell的實現。Shell.xaml文件包含了shell的佈局和部分UI元素,包括添加了模塊的視圖的區域的定義。

    下面的XAML展現了Shell結構以及主要的XAML元素。注意這個RegionName附加屬性被用來定義四個區域以及窗體背景圖片提供了shell的背景。

<Window x:Class="StockTraderRI.Shell">

 <!—shell background -->
 <Window.Background>
  <ImageBrush ImageSource="Resources/background.png" Stretch="UniformToFill"/>
 </Window.Background>

 <Grid>

   <!-- logo -->
   <Canvas x:Name="Logo">
    <TextBlock Text="CFI" ... />
    <TextBlock Text="STOCKTRADER" .../>
   </Canvas>

   <!-- main bar -->
   <ItemsControl 
    x:Name="MainToolbar" 
    cal:RegionManager.RegionName="{x:Static inf:RegionNames.MainToolBarRegion}">
   </ItemsControl>

   <!-- content -->
   <Grid>
    <Controls:AnimatedTabControl
     x:Name="PositionBuySellTab"
     cal:RegionManager.RegionName="{x:Static inf:RegionNames.MainRegion}"/>
   </Grid>

   <!-- details -->
   <Grid>
    <ContentControl 
     x:Name="ActionContent" 
     cal:RegionManager.RegionName="{x:Static inf:RegionNames.ActionRegion}">
    </ContentControl>
   </Grid>

   <!-- sidebar -->
   <Grid x:Name="SideGrid">
    <Controls:ResearchControl 
     cal:RegionManager.RegionName="{x:Static inf:RegionNames.ResearchRegion}">
    </Controls:ResearchControl>
   </Grid>

 </Grid>
</Window>

    Shell的後置代碼實現很是簡單。Shell被導出,目的是當啓動引導程序建立它時,它的依賴將會被MEF解析。shell的惟一依賴---ShellViewModel--在構造中被注入,以下所示。

C# Shell.xaml.cs
[Export]
public partial class Shell : Window
{
 public Shell()
 {
  InitializeComponent();
 }

 [Import]
 ShellViewModel ViewModel
 {
  set
  {
   this.DataContext = value;
  }
 }
}

    在後置代碼文件中的少許的代碼和視圖模型說明了組合應用程序結構的能力和簡單性。這種缺乏代碼也說明了在shell和組成它的視圖之間的解耦。定義區域

定義區域

 

你經過一個命名的位置定義視圖將會顯示的佈局,叫作區域。區域扮演爲一個用於在運行時展現一個或多個視圖的佔位符。模塊能夠定位和添加內容到佈局中的區域而不須要知道區域是如何以及在哪裏展現的。這使得佈局的變化將不會影響將內容添加到佈局的模塊。

    區域經過爲WPF或Silverlight中控件分配一個區域名稱來,要麼在前面展現的Shell.xaml文件中XAML中或者在代碼中來定義。區域能夠經過它們的名稱來被訪問。在運行時,視圖被添加到命名的區域控件中,這些區域控件而後根據視圖的實現的佈局策略來顯示這些視圖。例如。一個Tab控件區域將會將它的子視圖在一個分頁排列中佈局展現。區域支持添加或者移除視圖。視圖能夠經過代碼或者自動的被建立和展現在區域中。在Prism類庫中,前面的實現方式是經過視圖注入,後面的方式是經過視圖發現。這兩種技術肯定視圖如何單獨映射到該應用程序的用戶界面內,在指定的區域。

    應用程序的Shell定義了最高級別的應用程序的佈局;例如。經過指定主要內容和導航內容的位置,就像下面展現的。這些高級別視圖中佈局相似地被定義,從而容許總體的UI被遞歸組合。

clipboard[5]

    某些時候區域用於定義多個邏輯相關的視圖的位置。這種區域控件一般在派生自ItemsControl控件經過根據它的實現策略來展現視圖。例如在Stack或者Tabed佈局排列。

    區域也能夠用於定義一個單一視圖的位置;例如,經過使用一個ContentControl。在這種場景中,區域控件只能在同一時刻展現一個視圖,即便有多個視圖映射到了這個區域位置。

Stock Trader RI Shell Regions

    Stock Trader RI展現了單一視圖和多個視圖佈局方式,你能夠在程序的shell中看到這兩種方式,它們定義了應用程序的高級別的視圖的位置。下面的插圖展現了Stock Trader RI中shell定義的區域。

clipboard[6]

Stock Trader RI中在購買或者銷售股票時也展現了多視圖佈局。購買/出售區域是一個集合樣式區域展現了集合中多個購買/出售視圖(OrderCompositeView)的一部分,以下所示

clipboard[7]

    shell的ActionRegion包含OrdersView,OrdersView包含Submit All and Cancel All 按鈕和OrdersRegionOrdersRegion附加到了顯示多個OrderCompositeViewsListBox控件。

IRegion

一個區域是一個實現了IRegion接口的類,區域是承載了經過一個控件顯示的內容的容器。下面的代碼展現了IRegion接口。

public interface IRegion : INavigateAsync, INotifyPropertyChanged
{
  IViewsCollection Views { get; }
  IViewsCollection ActiveViews { get; }
  object Context { get; set; }
  string Name { get; set; }
  Comparison<object> SortComparison { get; set; }
  IRegionManager Add(object view);
  IRegionManager Add(object view, string viewName);
  IRegionManager Add(object view, string viewName, bool createRegionManagerScope);
  void Remove(object view);
  void Deactivate(object view);
  object GetView(string viewName);
  IRegionManager RegionManager { get; set; }
  IRegionBehaviorCollection Behaviors { get; }
  IRegionNavigationService NavigationService { get; set; }
}

在XAML中添加一個區域

RegionManager 應用了一個在XAML中簡化的建立區域的附加屬性。爲了使用這個附加屬性,你必須在XAML中引入Prism類庫的命名空間憨厚使用RegionName附加屬性。下面的實例展現瞭如何在一個AnimatedTabControl的窗口中使用這個附加屬性。這個實例在XAML中消除了魔法字符串。

    注意使用X:Static擴展標記來引用MainRegion字符內容。

XAML (WPF)
<Controls:AnimatedTabControl
  x:Name="PositionBuySellTab"
  cal:RegionManager.RegionName="{x:Static inf:RegionNames.MainRegion}"/>

    Silverlight4不支持X:Static。所以,你須要爲區域名稱使用字符串值,或者,可選的,爲每一個區域名稱定義一個應用程序級別的字符串資源。RegionName付附加屬性能夠綁定到這個字符串資源來解析區域名稱。

XAML (Silverlight)
<Controls:AnimatedTabControl 
 Regions:RegionManager.RegionName="MainRegion" />

使用代碼添加一個區域

    RegionManager能夠不使用XAML而直接註冊區域。下面的代碼示例展現例如如何從後置代碼文件中將一個區域添加到一個控件中。首先是要獲取一個區域管理的引用。而後,使用RegionManager靜態方法SetRegionManager和SetRegionName,區域附加到界面的ActionContent控件而後區域被命名爲AcontionRegion。

C#
IRegionManager regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
RegionManager.SetRegionManager(this.ActionContent, regionManager);
RegionManager.SetRegionName(this.ActionContent, "ActionRegion");

在區域加載時顯示區域內的視圖

    在視圖發現機制中,模塊能夠將視圖(視圖模型或者展示模型)註冊到指定名稱的位置。當這個位置在運行時被展示的時候,任何註冊到這個區域的視圖將會被自動地建立和展示。

    模塊在一個註冊表中註冊視圖。父視圖查詢這個註冊表來發現這些註冊到指定位置的視圖。在它們被發現以後,父視圖將會使用這些視圖來替換掉屏幕上的控件站位符。

    在應用程序加載之後,組合視圖被通知來處理已經被添加到註冊表中的心視圖的位置。

    下面的插圖展現了視圖發現方式。

clipboard[8]

    Prism類庫定義了一個標準的註冊表,RegionViewRegistry,來爲這些命名的位置註冊視圖。

    爲了在一個區域中顯示一個視圖,使用區域管理來註冊視圖,就像下面的代碼展現。你能夠在區域中直接註冊一個視圖類型,在這種狀況下,經過依賴注入容器這個視圖將會被構建而且在承載控件的區域加載的時候將視圖添加到這個區域中。

C#
// View discovery
this.regionManager.RegisterViewWithRegion("MainRegion", typeof(EmployeeView));

    可選的,你能夠提供一個返回顯示視圖的委託,例如所示的例子。區域管理器將會在區域建立的時候展現視圖。

C#
// View discovery
this.regionManager.RegisterViewWithRegion("MainRegion", () => this.container.Resolve<EmployeeView>());

UI Composition QuickStart 在員工模塊的ModuleInit.cs文件中有一個展現瞭如何使用RegisterViewWithRegion方法

的演示。

編程的方式顯示區域內的視圖

    在視圖注入的方式中,視圖管理它們的模塊經過編程的方式添加到一個命名的位置或從這個位置移除。爲了使用這點,應用程序在UI中包含了一個命名的位置的註冊表。一個模塊可使用這個註冊表查找某個位置而後經過編程將視圖注入到其中。爲了保證註冊表中的位置能夠被簡便的訪問,每一個命名的位置附着於用於注入的視圖的通用接口。下面的插圖展現了視圖注入方式。

clipboard[9]

    Prism類庫爲訪問這些位置定義了一個標準的註冊表,RegionManager,和一個標準的接口,IRegion

    爲了使用視圖注入來將一個視圖添加到區域中,從區域管理中得到區域,而後調用Add方法,以下代碼所示。在視圖注入中,視圖只有在模塊加載時或者預約義動做完成時被添加到了區域中以後才能被展現。

C#
// View injection
IRegion region = regionManager.Regions["MainRegion"];

var ordersView = container.Resolve<OrdersView>();
region.Add(ordersView, "OrdersView");
region.Activate(ordersView);

    另外,Stock Trader RI, the UI Composition QuickStart中都有書圖注入的演示。

導航

    Prism 4.0類庫包含了爲WPF和Silverlight應用程序中實現導航功能提供了豐富和兼容的導航API。

    區域導航是視圖注入的一種形式。當一個導航請求被處理時,它將會嘗試查找可以知足該請求的區域的視圖。若是它找不到合適的視圖,它將會調用應用程序容器來建立這個對象,而後將這個對象注入到區域中而後激活它。

    下面來自Stock Trader RI 中的 ArticleViewModel 代碼示例展現瞭如何初始化一個導航請求。

C#
this.regionManager.RequestNavigate(RegionNames.SecondaryRegion, 
 new Uri("/NewsReaderView", UriKind.Relative));

    關於區域導航的更多信息,參考第8章「導航」。View-Switching Navigation QuickStart 和 State-Based Navigation QuickStart 也演示了程序導航的實現。

區域中視圖排序

    不管使用視圖發現仍是使用視圖注入,應用程序均可能須要對在TabControlItemsControl,或任何其餘的顯示多個活動視圖的控件中的視圖進行排序。默認狀況下,視圖按它們被註冊和添加到區域中的順序進行顯示。

    當一個組合應用程序構建時,視圖常常從不一樣的模塊中進行註冊。聲明模塊間的依賴關係能夠緩解這個問題,可是當模塊和視圖都沒有讓你和實際的相互依存關係時,聲明一我的工的模塊間依賴耦合是沒必要要的。

    爲了容許視圖能夠參與它們自身的排序,Prism類庫提供了ViewSortHintAttribute屬性,這個屬性包含了一個容許視圖聲明一個它應該如何在區域中排序的Hint的字符串屬性。

    當展示視圖時,Region類使用一個使用了默認的按提示來排序視圖的視圖排序慣例。這是一個簡單的區分大小寫的排序順序。用於hint屬性的視圖被排到那些沒有hint屬性的視圖的前面。一樣,這些沒有hint屬性的視圖按它們被添加到區域的順序進行顯示。

    若是你想要改變視圖的排列順序機制,Region類提供了一個你能夠設置本身的Comparision<object>委託方法的SotrComparision屬性。他對於代表區域反映在UI上Views和ActiveViews的排列順序的屬性是很是重要的。由於這些適配器例如ItemsControlRegionAdapter直接綁定到這些屬性。一個自定義的區域適配器能夠實現它本身的重載了區域如何排列視圖的排序和篩選方式。

View Switching QuickStart演示了在導航區域的左手邊的一個簡單的數字模式來定義視圖的順序。下面的代碼實例展現了ViewSortHint應用了每一個導航視圖。

C#
[Export][ViewSortHint("01")]publicpartialclassEmailNavigationItemView
[Export][ViewSortHint("02")]publicpartialclassCalendarNavigationItemView

[Export][ViewSortHint("03")]publicpartialclassContactsDetailNavigationItemView

[Export][ViewSortHint("04")]publicpartialclassContactsAvatarNavigationItemView

多個區域之間共享數據

    Prism類庫提供了視圖之間通訊的多種實現方式。取決於你的應用場景。區域管理提供了RegionContext屬性做爲這些方式之一。

RegionContext在你想要在同一個承載的區域內的父視圖和子視圖之間共享上下文的時很是有用。RegionContext是一個附加屬性。在區域控件的上下文屬性設置值,那樣可使得全部在區域控件中展現的子視圖之間得到數據可用。區域上下文能夠是任意的很是簡單的或者負責的對象而且能夠是一個數據綁定的值。RegionContext能夠用於不管是視圖發現中仍是視圖注入中。

    注意:

    在Silverlight和WPF中,DataContext屬性被用來設置視圖的本地數據上下文。它容許視圖使用數據綁定來同視圖模型,本地表現,或者模型之間進行通訊。RegionContext用來在多個視圖之間共享上下文,而且不支持定位到單獨的視圖。它提供了一種在多個視圖之間共享上下文的簡單機制。

    下面的代碼展現瞭如何在XAML中使用RegionContext附加屬性。

XAML
<TabControl AutomationProperties.AutomationId="DetailsTabControl"
  cal:RegionManager.RegionName="{x:Static local:RegionNames.TabRegion}"
  cal:RegionManager.RegionContext="{Binding Path=SelectedEmployee.EmployeeId}"
  ...>

    你也能夠在代碼中設置RegionContext,以下所示。

C#
RegionManager.Regions["Region1"].Context = employeeId;

爲了在視圖中取回RegionContext,使用RegionContext類的GetObservableContext靜態方法。它將視圖做爲參數傳遞而且而後訪問它的Value屬性,以下所示。

C#
private void GetRegionContext()
{
  this.Model.EmployeeId = (int)RegionContext.GetObservableContext(this).Value;
}

    RegionContext的值能夠從視圖中經過簡單的分配一個新值的Value屬性改變。視圖能夠選擇經過訂閱GetObservableContext方法返回的ObservableObject對象的PropertyChanged事件來在RegiongContext屬性發生改變時背通知。這使得多個視圖在它們的RegionContext發現變化時保持同步。下面的代碼演示了訂閱PropertyChanged事件。

C#
ObservableObject<object> viewRegionContext = 
               RegionContext.GetObservableContext(this);
viewRegionContext.PropertyChanged += this.ViewRegionContext_OnPropertyChangedEvent;

private void ViewRegionContext_OnPropertyChangedEvent(object sender, 
                   PropertyChangedEventArgs args)
{
  if (args.PropertyName == "Value")
  {
    var context = (ObservableObject<object>) sender;
    int newValue = (int)context.Value;  
  }
}

    注意:

RegionContext被設置爲區域的承載的內容對象的附加屬性。這意味着內容對象必須派生自DependencyObject。視圖是一個但是控件,它最終派生自DependencyObject。若是你選擇使用WPF或者Silverlight數據模板來定義你的視圖,內容對象將會表現爲視圖模型或者展示邏輯。若是你的視圖模型或表現模型須要取回RegionContext,它須要派生自DependencyObject基類。

建立區域的多個實例

    範圍內的區域是僅適用於視圖注入。若是你須要一個擁有它本身的區域實例的視圖的時候你應該使用它們。定義區域的視圖的附加屬性自動繼承它們父區域的RegionMangaer。一般,這是一個在Shell窗口中註冊的全局的RegionManager。若是應用程序建立了視圖的多個實例,每一個實例將會嘗試註冊它的區域中的RegionManager。RegionMangaer容許名稱不重複的區域;所以,第二次注入將會產生一個錯誤。

    做爲代替,使用區域範圍能夠是每一個視圖擁有它本身的RegionManager而且它的區域將會註冊到RegionManager中而不是註冊到父RegionMangaer,以下圖所示。

clipboard[10]

    爲了建立視圖的一個本地RegionManager。指定的新的RegionManager應該在你添加視圖到區域中時建立。以下所示。

C#
IRegion detailsRegion = this.regionManager.Regions["DetailsRegion"];
View view = new View();
bool createRegionManagerScope = true;
IRegionManager detailsRegionManager = detailsRegion.Add(view, null, 
                            createRegionManagerScope);

Add方法將返回新RegionManager該視圖能夠保留進一步訪問本地範圍。

建立Views

    應用程序的視覺展示能夠採用多種形式,包括用戶控件,自定義控件,和數據模板,僅舉幾例。在Stock Trader RI中,用戶控件經常使用於在主窗口中展示不一樣的部分,可是這不是一個標準。在你的應用程序中。你應該你應該使用你最熟悉和最適合你工做的方式。不管您的應用程序爲主視覺表現,你將不可避免地使用用戶控件,自定義控件和數據模板的組合在總體設計中。下面的插圖展現了Stock Trader RI中中使用的幾項。這個插圖也做爲後面幾節的服務,在後面將會單獨描述每項。

clipboard[11]

用戶控件

    Blend和Visual Studio 2010都爲建立用戶控件提供了豐富的支持。使用這些工具建立的用戶控件所以被推薦使用Prism類庫建立UI內容。如本主題前面提到的,Stock Trader RI普遍的使用它們建立了將會插入到區域中的內容。WatchListView.xaml用戶控件就是內部包含了WatchModule的一個簡單的UI展示的很好的例子。這種控件是簡單的使用這種模型的簡單控件。

自定義控件

    在一些狀況下,一個用戶控件太受限了,在這些狀況下,自定義佈局或者可擴展性比這種易建立性更重要了。這就是自定義控件很是有用的地方了。在the Stock Trader RI中,餅狀圖控件就是一個很好的例子。這個控件是從所述位置導出的數據組成的。而且顯示爲一個圖標的總體組合。建立這種類型的控件比建立用戶控件更具一些小的挑戰性。相比於用戶控件,它限制了Blend和Visual Studio2010對可視化設計的支持。

數據模板

    數據模板是這種數據驅動應用程序的一個重要的部分。在the Stock Trader RI中,使用基於集合的控件對數據模板的使用很是流行。在許多狀況下,你可使用一個數據模板來建立一個完整的可視化展示而不須要建立任何類型的控件。ResearchRegion使用了一個數據模板來顯示文章並與一個物品風格相結合,提供了一種指示其項被選定。

    Blend對於數據模板有豐富的可視化設計支持。Visual Sutdio 2010只提供了使用XAML編輯器來編輯數據模板的支持。

資源

資源例如樣式,資源字典和控件模板能夠分散在應用程序中。在一個組合的應用程序中尤爲是這樣。當你考慮在哪裏放置資源,特別要注意UI元素和它們所須要的資源之間的依賴關係。在Stock Trader RI 解決方案中,以下面的插圖所示,包含了代表各類資源能夠存在的地方的標籤。

clipboard[12]

應用程序資源

    一般,應用程序資源是能夠被整個程序訪問的資源。這些資源每每集中在應用程序根上,可是它們也能夠提供一個爲模塊和控件的基本類型的默認樣式。這樣的一個例子是應用到根應用文本框中鍵入文本框樣式。這種風格將提供給全部文本框的應用程序,除非被模塊或控件水平的樣式覆蓋。

模塊資源

    模塊資源扮演着與應用程序根資源相同的角色,它們而已被模塊中全部的項目使用。使用這種級別的資源能夠爲整個模塊提供統一的界面而且也能夠容許重用在跨越一個或多個可視化組件的指定實例。模塊級別的資源的使用應該被包含在各自的模塊中。建立模塊之間的依賴關係可能會致使難以在用戶界面元素顯示在錯誤的定位問題。

控件資源

    控件資源一般包含在空間類庫中,而且能夠用於整個控件庫中全部的控件。這些資源趨於用於最有限的區域內,由於控件庫一般包含特定的控件而且不包含用戶控件(在基於Prism類庫的應用程序中,用戶控件一般放在它們被使用的模塊中)。

UI設計指導

    本主題的目的是爲XAML設計人員和使用Prism類庫開發WPF或Silverlight應用程序的開發人員體統一些高級別的指導。本主題描述了UI佈局,可視化展示,數據綁定,資源和展示模型。在閱讀了本主題以後,你將會對於如何基於Prism類庫設計應用程序的UI有更深層次的理解。以及理解一些能夠幫助你建立易維護UI的組合應用程序的技術。

用戶界面設計指導

    基於WPF和Silverlight標準規則的使用Prism類庫建立的組合應用程序的佈局---使用了包含相關項目的面板概念的佈局。然而,在組合應用程序中,面板內的各類內容是動態的而且在設計時是並不被知道的,這就要求設計人員和開發人員建立能夠包含佈局內容的頁面框架而後設計適應這些佈局的元素。做爲一個設計人員或者開發人員,這意味這你必須考慮Prism類庫中的兩個主要的佈局概念:容器組合和區域。

容器組合

    容器組合在實際上僅僅是WPF和Siliverlight本質上提供的容量模型的一種擴展。container次能夠表明任何元素,包含窗口,頁面,用戶控件,面板,自定義控件,控件模板,或者數據模板,它能夠包含其餘元素。

    你如何想象你的UI可能因實現而不一樣,可是你將會發現反覆出現的主題。你將會建立一個窗口,頁面或者包含了固定內容和動態內容的用戶控件。固定的內容將會包括包含的UI內容的整個架構,動態內容將會是區域內的一個位置。

    例如,WPF Stock Trader RI有一個名爲Shell.xaml的窗口包含了應用程序的總體結構。下面的插圖展現了在Blend中加載的Shell。注意只有一些固定的UI部分是可見的。Shell的其餘部分是在應用程序加載模塊時動態的插入到不一樣的區域內的。

    在這樣類型的應用程序中設計時的經驗會有一些限制,可是在實際上你所知道的將會在運行時被放到不一樣的區域內的內容正是你須要設計的。來看這樣的一個例子,比較如下下一張插圖的主頁面的設計和後面的一張插圖中運行時的視圖。在設計人員的視圖中,與運行時的包含了一個包含一個位置數據的Tab控件,一個趨勢線,餅圖和與選中的股票相關的新聞區域的界面相反,這個頁面絕大部分是空的。在設計人員的視圖與運行時的視圖的不一樣展現了設計人員和開發人員在它們使用Prism類庫建立應用程序時面臨的調整。

    設計時看不到這些項,所以肯定它們多大以及它們怎樣適應整個應用程序的界面就有一些困難。在你建立你的容器的佈局時考慮如下幾點:

  • 是否有任何尺寸的限制,是否可能限制內容的大小?若是有的話,考慮使容器支持滾動。
  • 考慮使用Expand而和ScrollViewer來整合須要將大量的動態的適應到有限的空間中的狀況。
  • 密切關注在屏幕內容增加時內容將會如何放大來確保你的應用程序界面能夠適應任何分辨率。

clipboard[13]

clipboard[14]

在設計時整合應用程序視圖

    前面兩個插圖中,在工做的挑戰之一就是在運行時組合高級別的視圖。在組合應用程序中的每個UI元素都必須被單獨的設計。這使得很難想像在運行時的組合頁碼將會是什麼樣子。爲了可以想象到組合視圖的在組合狀態下的樣子。你能夠建立一個包含了你想要測試的全部UI元素的視圖的測試工程。

    另外,考慮使用Blend工具中的設計時的樣例數據功能和Visual Studio 2010來使用數據填充UI元素。設計時數據對於使用數據模板,集合控件,圖,表等工做很是有幫助。更多信息,請看「設計時樣例數據指導」一節。

佈局

    當你設計一個組合應用程序的佈局時考慮如下幾項:

  • Shell定義應用程序的主要佈局。每一個佈局的面是一個區域而且應該保持爲一個空的容器。不要在設計時替換區域內的內容由於內容將會在運行時加載。
  • Shell應該包含背景,標題和頁腳。將Shell想象成ASP.NET中的母版頁。
  • 若是shell區域有固定尺寸,視圖應該使用動態大小。
  • 視圖可能會要求固定高度和動態寬度。這一點的一個例子就是Stock Trader RI中側邊欄的PositionPieChart視圖。
  • 其餘視圖可能要求動態高度和寬度。例如。Stock Trader RI中一側邊欄的NewsReader。它自身的高度取決於標題的長度,而且它的寬度應該一直適應區域的大小(側邊欄的寬度)。相同的應用項就是PositionSummaryView視圖中的表格的寬度應該適應屏幕的大小以及高度應該適應表格中行數量。
  • 視圖一般應該有透明的背景,使得Shell背景來做爲應用程序的可視化的背景。
  • 常常爲指定顏色,畫刷,字體和字體大小使用命名的資源,而不是直接在XAML中指定屬性值。這樣可使應用程序更便於維護。這也使得應用程序可在運行時反映資源字典的變化。

動畫

    當你在在Shell或者視圖中使用動畫的時候考慮如下幾點:

  • 你能夠在Shell的佈局上使用動畫,可是你必須對它的內容和視圖單獨的應用動畫。
  • 每一個視圖單獨的設計和設置動畫
  • 使用平滑柔和的動畫來提供一個UI元素進入視圖或從視圖中移除的可視化線索,這給應用程序一種光滑的外表和感受。

    Blend提供了一系列豐富的行爲,緩動函數,和一個優秀的動畫編輯體驗以及基於可視化狀態變化或事件的轉換UI元素。更多信息,請看MSDN上的"VisualStateManager Class"

運行時優化

    爲性能優化考慮如下幾項:

  • 將任何的通用資源放置在App.xaml文件或使用合併資源字典來避免樣式的重複
  • 在Silverlight中,避免爲指定的應該與應用程序其餘部分(例如,應用程序主題)區別樣式的靜態的文本使用非系統的字體。在這種狀況下,肯定是否將文本轉換爲路徑或者使用嵌入的字體會更好。嵌入一種字體可能影響到下載.xap文件的大小由於有些字體文件至關大。爲了最小化下載.xap文件的大小,Blend容許你之下在字體的符號特徵來替代整個字體。更多信息請看"Using Custom Fonts in Silverlight."

設計時優化

     接下來的幾節將會描述設計時的場景而且爲最大限度地利用了設計時體驗提供解決方案。

擁有許多XAML資源的大的解決方案

    在應用程序中有許多XAML資源是解決方案的一部分,可視化設計器加載時間將會收到影響,某些狀況下將會很是嚴重。由於可視化設計器必須轉化合並XAML資源,這會存在性能的降低。解決這個問題的方案就是將全部的XAML資源移到另外一個解決方案中,編譯那個解決方案,而後從那個大的方案的DLL中引用新的XAML資源。由於XAML資源在引用的二進制程序集中,可視化設計器將會不轉換XAML資源,這樣就提升了設計時的性能。當移動XAML資源到一個擴展的程序集時,你可能須要考慮爲你的資源暴露CompoentResourceKeys。更多信息,請看MSDN上的「"ComponentResourceKey Markup Extension」。

XAML 資產

    XAML對於建立例如圖片,圖形和3D場景等資產來講是一種有力和富有表達性的語言。一些開發者和設計者偏向建立XAML資產來替代使用.ico,.jpg,或者.png圖片文件。一個緣由是選擇XAML的方式利用了依賴於XAML渲染解決方案的優點。另一個緣由是它們可使用Expression工具包中的工具來創須要的資產來設計它們的應用程序。

    若是解決方案中有許多這樣的資產,設計器在在設計時的加載效率就會受到影響,將這些資產轉移到其餘的單獨的DLL中能夠解決這個性能問題。將資產移動到單獨的DLL中還能夠在多個解決方案中達到重用這些資產的目的。

可視化設計與引用程序集

    一個移動XAML資源和資產到一個引用的二進制程序集中的不幸的負面影響就是Blend和Visual Studio 2010 的編輯器可能不會列出位於二進制引用的程序集資源。這意味着你將不可以從工具提供的資源選擇器中挑選一個命名的資源了。相應的,你將須要資源名稱的類型。

Silverlight 設計時App.xaml 資源

    Silverlight的組合應用,能夠構成多種方式,以容許組件的運行時的延遲加載,或減小初始的.xap下載大小。你可使用一個策略是建立主Silverlight應用程序,而後建立每一個附屬程序集的模塊。當你添加附屬程序集時,你能夠選擇其中一個應用程序項目模板或者Silverlight類庫模板。

    爲附屬程序集選擇一個Silverlight應用程序項目模板能夠提供一個部署的好處:當程序集建立時將會被打包成一個.xap文件。然而,這樣的作法對於可視化設計器的負面影響就是當不知一個Silverlight應用程序表如今單獨的解決方案中時。主Silverlight應用程序須要將它的應用程序資源在App.xaml中合併。這樣的問題就是可視化設計器會消耗暴露在App.xaml中的資源。由於在解決方案中有不止一個Silverlight應用程序。可視化設計器不會嘗試從另外的Silverlight應用程序中使用資源;想法,它只會使用正在活躍着的Silverlight應用程序的那些資源。

    Blend 4提供了這個問題的一個解決方法。當Blend察覺到這種狀況是,它會彈出一個讓你選擇一個用於解決方案中全部工程之間的設計時資源字典的對話框。

    Visual Studio 2010 沒有這樣的功能;所以,附屬的Silverlight應用程序集將不會有很是豐富的設計時體驗觸發你在本地程序集中合併了應用程序級的資源。若是你爲了一個更好的可視化設計體驗而選用合併應用程序級資源。你必須記住在你部署你的應用程序以前將它們移除。

建立設計友好的Views指導

    如下是設計一個友好的應用程序擁有的一些特徵:

  • 同使用Visual Studio 和Blend設計器它提供了豐富的編輯體驗
  • 它是工具可用的(Tooling-enabled).例如,它容許你使用綁定構建工具
  • 它在須要時提供了一個設計時的樣例數據
  • 它容許在設計時執行代碼而不引發未處理的異常

如下動做在編輯期間將會執行屢次。設計者不友好的用戶代碼將會引發一個或多個這些動做失敗,這將會削減開發者好設計者的生產率和創造率。

  • 設計界面動做:
    • 構建對象
    • 加載對象
    • 設置屬性值
    • 執行設計界面的手勢
    • 使用一個控件做爲跟元素
    • 在一個控件中承載另外一個控件
    • 重複性的打開關閉XAML文件
    • 從新構建項目
    • 從新加載設計器
  • 綁定構建動做:
    • 發現DataContext
    • 列出可用的數據源
    • 列出數據源類型屬性
  • 設計時樣例數據動做:
    • 在設計界面使用控件正確的展現樣例數據

設計時編碼

    爲了給你一個豐富的設計時的體驗,Visual Studio和Blend設計器在設計時實例化了對象而且運行代碼。然而,因爲在類型被實例化以前嘗試訪問其引用而引發的空引用異常而致使加載失敗的高百分率以及沒必要要的設計時異常。

    下表列出了差的設計時體驗的主要緣由。經過避免如下問題及使用技術減輕這些問題,設計時體驗和生產率將會極大的加強,而且開發人員與設計人員之間的工做流程也將會更加順暢。

避免這些用戶代碼

Visual Studio 2010

Blend 4

在設計時旋轉(Spinning)多個線程,例如,在設計時的Loaded事件或者構造方法中中實例化和開始一個Timer。

X

X

在設計時使用引發棧溢出的控件。

使用嘗試遞歸加載自身的控件

X

X

在轉換器或者數據模板選擇器中拋出空引用異常

X

X

在構造方法中拋出空引用異常或其餘異常。 它們一般有如下引發:

  • 在設計時使用調用從數據庫或者網絡返回數據的業務或者數據層的代碼
  • 嘗試經過MEF,控制反轉,或者位置定位器在啓動引導程序或容器初始化代碼運行以前解析依賴關係

X

X

在控件或者用戶控件的Loaded事件中拋出空引用異常或者其餘異常。這種常在你假設控件的狀態在運行時多是true可是在設計時卻不是true時發生

X

X

在設計時嘗試獲取Application或Application.Current對象

X

X

在WPFUserControls中使用StaticResource.

X

建立很是大的項目

X

設計時 用戶代碼問題緩解

    少許的預防性代碼實踐將會消除前面表格中描述的大部分的問題。然而,在你能夠緩解設計時用戶代碼問題以前,你必須理解你的應用程序控件和代碼將會被設計器在的一個未初始化的應用程序域中隔離的執行。在這裏,未初始化的意思是指一般的啓動,引導程序,或者初始化代碼還未運行時。

    當你的應用程序在運行時執行的時候,App.xaml.cs文件中的啓動代碼將會運行。若是你的程序中有依賴哪裏的代碼,這些代碼將會不在設計時執行。若是你尚未預料到你這裏的代碼,將會發生沒必要要的異常。(這就是爲何在設計時嘗試獲取Application或Application.Current對象將會引起異常的緣由了),爲了緩解這些問題:

  •     用於不要假設引用的對象將會在設計時代碼中被實例化。在設計時能夠被執行的代碼,一直執行在獲取任何引用對象前檢查是否爲空。
  • 若是你的代碼訪問了Application或者Application.Current對象,在獲取這個對象以前進行是否爲空的檢查。
  • 若是你的構造方法或者Loaded事件處理程序中須要運行復雜的代碼或者須要訪問數據庫或調用網絡結果的代碼,考慮如下幾種解決辦法:
    • 將代碼包裝到一個經過調用如下之一的System.ComponentModel DesignerProperies方法來肯定代碼是否在設計是運行的檢查中
      • WPF:DesignerProperties.GetIsInDesignMode
      • Silverlight:DesignerProperties.IsInDesignTool
    • 不是在構造器或者Loaded事件處理程序中直接運行代碼,而是將這些調用抽象到接口後面的一個類中,而後使用許多技術之一來解析不一樣的依賴信息在設計時,運行時和測試時。例如,不是直接調用數據服務來檢索數據,而是將數據服務調用包裝到一個經過接口暴露方法的類中,而後,在設計是,使用模擬或這設計時對象來解析這個接口。

設計時理解用戶控件代碼什麼時候

    Blend和Visual Studio 都使用根對象的模型在設計器面板中展現。這對於提供被要求的設計體驗就很是必要了。由於跟對象是被模擬的,它的構造器和Loaded事件代碼在設計時不會被執行。然而,場景中的剩餘的控件被正常的構造,而且它們的Loaded事件會像運行時同樣引起執行。

    在下面的插圖中,根Windows構造器和Loaded事件代碼不會被執行。子用戶控件的構造器和Loaded事件將會被執行。

clipboard[31]

    這些概念很是重要,尤爲是若是你正在構建組合應用程序或者構建那些在運行時動態構建的應用程序。

    大多數的視圖是單獨編碼和設計的。由於它們被單獨的設計,一般在設計器中它們就是根對象。所以,它們的構造器和Loaded事件代碼永遠不會執行。

    然而,若是你將相同的用戶控件放到設計界面的另外的一個控件中,這個被隔離的用戶控件的代碼在設計時就會馬上執行。若是你沒有遵循上述剪切設計時代碼問題的實踐,承載控件將會變得不友好而且引發設計器的加載問題。

設計時屬性

    內建的「d:」設計時屬性提供了一個成功達到設計時工具體驗的平滑的道路。

    咱們須要解決的問題是如何提供一個Shape來在設計時綁定這個構造工具。在這種狀況下,Shape就是一個實例化的能夠在綁定的構建器上反映的類型,而後在構建綁定時列出這些屬性。

Shape也提供了設計時樣例數據,樣例數據在「設計時樣例數據指導」一節講到。

    「d:」屬性和擴展標記是設計命名空間的一個別名,這個設計了一系列的屬性。下面是在MSDN上一些涉及到「d:」屬性和擴展標記的鏈接:

「d:」屬性和擴展標記不能在代碼中被建立和擴展;它們只能在XAML中使用。「d:」屬性和擴展標記不被編譯到你的應用程序中;它們只是在Visual  Studio 和Blend工具中使用。

d:DataContext屬性

    d:DataContext,爲控件和子控件指定設計時數據上下文。當指定d:DataContext時,你也應該一同提供與運行是DataContext同樣的Shape的設計時DataContexgt。

若是爲一個控件同時指定了DataContextd:DataContext,開發工具將會使用d:DataContext。

d:DesignInstance 標記擴展

    若是擴展標記對於你來講仍是新知識,請閱讀MSDN上的"Markup Extensions and WPF XAML"。

    d:DesignInstace返回一個你將會在設計器中想要將其指定爲控件綁定的數據源的類型(「Shape」)實例。這個類型不須要去建立來用於肯定Shape。下表解釋了 d:DesignInstace擴展標記的屬性。

擴展標記屬性

定義

Type

將被建立的類型的名稱。類型是構造方法中默認的參數。

IsDesignTimeCreatable

指定的類型是否可用被建立?若是不能夠, 一個仿類型而不是真實的類型將會被建立。默認值是false

CreateList

若是是真,返回一個制定類型的通常集合。默認值是false

d:DataContext經常使用場景

    下面的三個示例代碼演示了一個鏈接最多的視圖和視圖模型的可重複的模式,以及可用的設計工具。

PersonViewModel PersonView運行是的一個依賴項。然而,在實例的視圖模型是很是的簡單的。真實世界裏的視圖模型一般會擁有一個或多個額外須要解析的依賴,而且這些依賴項一般被注入到它們的構造器中。

    當PersonView被構建時,它依賴的PersonViewModel將會被構建而且它的依賴關係將會經過一個依賴注入容器被解析。

    注意:

    若是視圖模型沒有須要解析的額外的依賴項,視圖模型能夠在視圖的XAML中北實例化,而且不會要求它的DataContext和d:DataContext。

C# PersonViewModel.cs
[Export]
public class PersonViewModel {

 public String FirstName { get; set; }
 public String LasName { get; set; }

}
C# PersonView.xaml.cs
[Export]
public partial class PersonView : UserControl
{
 public PersonView()
 {
  InitializeComponent();
 }

 [Import]
 public PersonViewModel ViewModel
 {
  get { return this.DataContext as PersonViewModel; }
  set { this.DataContext = value; }
 }
}

    這是鏈接視圖和視圖模型的很好的模式;然而,它使得在設計時視圖並不知曉它的DataContext的shape(視圖模型)。

    在下面的XAML實例中,你能夠看到d:DesignInstance擴展表演用於Grid來返回一個PersonViewModel的仿的實例。這個實例經過d:DataContext被暴露。做爲結果,Grid的子空間將會繼承d:DataContext,使得設計工具能夠發現並使用它的類型和屬性,結果就是使得開發者和設計者的更生產率的設計體驗。

XAML PersonView.xaml
<UserControl 
 xmlns:local="clr-namespace:WpfApplication1"
 x:Class="WpfApplication1.PersonView"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
 mc:Ignorable="d" 
 d:DesignHeight="300" d:DesignWidth="300">

 <Border BorderBrush="LightGray" BorderThickness="1" CornerRadius="10" Padding="10">

  <Grid d:DataContext="{d:DesignInstance local:PersonViewModel}">
   <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
   </Grid.RowDefinitions>
   <Grid.ColumnDefinitions>
    <ColumnDefinition Width="100" />
    <ColumnDefinition Width="Auto" />
   </Grid.ColumnDefinitions>

   <Label Grid.Column="0" Grid.Row="0" Content="First Name" />
   <Label Grid.Column="0" Grid.Row="1" Content="Las Name" />

   <TextBox 
    Grid.Column="1" Grid.Row="0" Width="150" MaxLength="50" 
    HorizontalAlignment="Left" VerticalAlignment="Top"
    Text="{Binding Path=FirstName, Mode=TwoWay}" />
   <TextBox 
    Grid.Column="1" Grid.Row="1" Width="150" MaxLength="50" 
    HorizontalAlignment="Left" VerticalAlignment="Top"
    Text="{Binding Path=LasName, Mode=TwoWay}" />

  </Grid>
 </Border>

</UserControl>

    注意:

    附加屬性和視圖模型定位器解決方案

    在開發者社區裏還有幾種可選的用於關聯視圖和視圖模型的技術。其中一種解決方案在運行時起到很強的做用可是在設計時一般不起做用。這種解決方法之一就是使用附加屬性和視圖模型定位器來關聯到視圖的DataContext。視圖模型定位器被要求使用是由於那樣視圖模型能夠被構建以及它的依賴項能夠被解析。

    這種解決方案的問題是你必須也要包含d:DataContext-d:DesignInstance組合由於可視化設計器工具不能反映d:DesignInstance的附加屬性的結果。不管你在應用程序中實現的哪一種技術來解決設計時shape,最重要的目標就是在應用程序中保持一直。一致性可使得應用程序維護起來更加見到那而且將產生成功的工做流程。

設計時樣例數據指導

    WPF和Silverlight 設計團隊發佈了深刻的,基於場景針對訓練的文章討論了在WPF和Silverlight項目中使用樣例數據。這篇文章

"Sample Data in the WPF and Silverlight Designer,"能夠在MSDN上獲取。

使用設計時樣例數據

    若是你使用一個可視化設計工具,好比Blend或者Visual Studio 2010,設計時樣例數據變得很是重要。視圖能夠被數據和圖片填充,這使得設計任務變得更容易更快度的完成。這樣的結果就是生成率和創造力的提升。

    包含數據模板的空集合控件只有在被填充了數據以後纔會可見。這使得編輯空集合控件的任務話費更多的時間由於你須要運行應用程序來查看最近一次修改後在運行時的樣子。

樣例數據源

    你可使用如下任何一種來源的樣例數據:

  • Expression Blend XML樣例數據
  • Expression Blend 4和Visual Studio 2010 XAML 樣例數據
  • XAML 資源
  • 代碼

    這些來源的每一種數據將會在下面講述。

Expression Blend XML 樣例數據

    Expression Blend中爲您提供了快速建立一個XML模式和填充相應的XML文件的能力。這種實現不依賴任何項目類。

    樣例數據類型的目的是讓設計人員可以快速的開始它們的項目,不須要等待一個開發人員或者在應用類能夠被使用以前。

    雖然大多數的樣例數據都支持Blend和Visual Studio 設計器,可是XML樣例數據只是Blend的功能且並不支持在Visual Studio 設計器中呈現。

    注意:

    在項目構建時XML樣例數據不會被編譯或者添加到程序中;然而,XML S車馬會被編譯到構建的程序集中。

Expression Blend 4 and Visual Studio 2010 XAML 樣例數據

在Blend 4和Visual Studio 2010的開始,d:DesignData擴展標記被添加儘可能,這使得設計時能夠加載XAML樣例數據。

    樣例數據XAML文件包含了一個或多個類型及關聯到其屬性的值的實例的XAML。

    d:DesignData有一個使用一個統一資源定位符(URI)來獲的位於項目中XAML文件中的樣例數據的Source屬性。d:DesignData擴展標記加載    XAML文件,轉換而後返回一個對象圖表。這個對象圖標能夠經過d:DataContext屬性,CollectionViewSource d:DesignSource 屬性, 或 DomainDataSource d:DesignData 屬性被使用。

    d:DesignData擴展標記客服的挑戰之一就是它得意建立非可建立的樣例數據。例如,WCF Rich Internet Application (RIA)服務實體---派生的對象不能在代碼中建立。另外,開發人員可能會有他們自已的不能建立的類型,可是仍然但願擁有這些類型的樣例數據。

    你能夠在Solution Explorer 中經過設置樣例數據文件Build Action屬性來改變d:DesignData來如何處理你的樣例數據文件,以下:

  • Build Action = DesignData – 仿製類型將會被建立
  • Build Action = DesignDataWithDesignTimeCreatableTypes – 真實類型將會被建立

    注意:

    在下面的插圖中,Custom Toll屬性是空的。這就要求樣例數據可以恰當的工做。默認狀況下,Blend  經常會設置這個屬性爲空值。

    當你使用Visual Studio 2010來添加一個樣例數據文件時,你一般會添加一個資源字典項而且從哪裏編輯它。在那種狀況下,你必須設置Build Action而且清空Custom Tool屬性。

clipboard[32]

    Blend提供了快速建立和綁定XAML樣例數據的工具。XAML樣例數據能夠在Visual Studio 2010 設計器中被使用和查看,以下圖所示。

clipboard[33]

    在生產了樣例數據以後,數據將會顯示在數據面板中,以下圖所示。

clipboard[34]

    而後你能夠將它拖到視圖中的根元素上,例如UserControl,而且將它設置到d:DataContext屬性。你也能夠將樣例數據拖拽到items Controls上,而且Blend將會將數據與控件進行關聯。

    注意:

    XAML樣例數據不會被編譯或者包含到構建的程序集中。
XAML資源

    你能夠在XAML中建立一個包含了指望類型的實例的資源,而後將那個資源綁定到DataContext屬性或者一個集合控件上。

    這種技術能夠用於快速建立用於若是不使用樣例數據將會花費很長時間來編輯數據模板的捨棄式樣例數據。

代碼

    若是你喜歡在代碼中建立樣例數據,你能夠寫一個暴露屬性或方法來爲它們的使用者返回數據的類。例如,你能夠寫一個在類中默認的空構造方法中填充了多個Customer類的實例的Customers類。每個Customer實例將會有合適的屬性值來設置。

    你可使用樣例數據類的一種方法是使用前面講到的d:DataContext,d:DesignInstace組合,確保將

d:DesignInstanceIsDesignTimeCreatable屬性設置爲true。

IsDesignTimeCreatable必須設置爲true的緣由是你想要使用者構造方法來執行那樣類中的代碼將會運行。若是使用者被做爲一個模仿類型來對待,使用者的代碼將永遠不會運行而且只有「shape」將會被工具發現。

下面的XAML實例實例化了Customers類,而且將其設置到d:DataContext屬性。Grid的子控件可使用Customers類暴露的數據。

XAML
<Grid d:DataContext="{d:DesignInstance local:Customers, IsDesignTimeCreatable=True}">

UI佈局關鍵決定

    當你開始一個組合應用程序項目時,須要作一些未來會很難改變的UI設計決策。通常來講,這些決策時普遍應用的而且他們的一致性將會幫助開發者與設計者的生產力。

    如下是一些重要的UI佈局決策:

  • 決定應用程序流並相應地肯定區域
  • 決定每一個區域將會使用的加載的視圖類型
  • 決定你是否想要使用區域導航API
  • 決定你將會使用那種設計模式(MVVM,展示模式等等)
  • 決定樣例數據策略

更多信息

關於擴展Prism類庫的更多信息,請參考"Extending Prism."

關於命令的更多信息,請參考第5章, "Implementing the MVVM Pattern."的"Commands"

關於綁定的更多信息,請參考 第5章,"Implementing the MVVM Pattern.""Data Binding"

關於區域導航的更多信息,請參考第8章, "Navigation."

關於本主題中討論的指導內容,請參考如下:

相關文章
相關標籤/搜索