隨著IOS7由之前UI的擬物化設計變為如今的扁平化設計,也許扁平化的時代要來了,當然我們是不是該吐槽一下,蘋果什麼時候也開始跟風了,自GOOGLE和微軟界面扁平化過後,蘋果也加入了這一隊伍。
AvalonDock
AvalonDock 是一個.NET庫,用於在停靠模式布局(docking)中排列一系列WPF/WinForm控件。最新發布的版本原生支持MVVM框架、Aero Snap特效並具有更好的性能。
AvalonDock 2.0版本已經發布了,新版本是用MVVM框架重新編寫,似乎也用了Command(命令)模式。2.0版的文檔尚未發布,但你可以參考Avalon.TestApp 或者2.0版源碼中的Avalon.MVVMTestApp文件夾來查看新的API。
這個庫使用很簡單——只需要用AvalonDock提供的控件包含你自己的控件,頁面布局就立即變成可停靠的(dockable)。可以參考 入門 頁面獲取樣例代碼,了解不同控件的特性。當然你也可以在自己的C#代碼中實例化或操作這些控件。2.0版本中,控件功能與以前一致,但控件名稱已經改變,因此建議參考前述樣例代碼直至參考文檔更新為止。
大名鼎鼎SharpEevelop也應用了AvalonDock,由於SharpEevelop的框架過於龐大,並且SharpEevelop裡的AvalonDock 1.3的版本,並不支持MVVM的模式,所以就興起了自己做一個插件式系統,當然也跟一下扁平化的風,目前框架已經做好並應用到個人項目中,本著開源的思想我會把框架搭建的過程,以及遇到的種種問題分享出來。
Caliburn.Micro
Caliburn是Rob Eisenberg在2009年提出的一個開源框架,可以應用於WPF,Silverlight,WP7等,框架基於MVVM模式,像它的名字一樣,是企業級應用的一把利器。
基於WPF的框架有很多,Prism,WAF等,每個框架都有自己側重點,像Prism側重於模塊間的組合,WAF側重於分層設計。通觀CM的設計,它的一些想法如下: 1.ActionMessage,結合了Blend中的TriggerAction,可以把UI控件中的事件綁定到後台方法,類似於CallMethodAction。CM對ActionMessage進行了很多擴展,包括可以傳入多個參數,參數支持綁定,可以通過CanExecute作執行前判斷並設置控件的Enable等。
2.Conventions,協定,這個詞聽上去有點虛,其實就是智能匹配的意思。CM制定了一系列匹配的規則,比如說View和ViewModel之間的匹配,綁定時傳入控件名可以找到控件,傳入方法名可以綁定到方法等等。
3.Screen和Conductor,作為一個Presentation的框架,各個UI部件(Widget或者叫Pad)的管理是必不可少的。Screen就是用來表示UI部件的,它定義了一些列UI部件的生命期事件,比如Activated,DeActivated等。Conductor是用來管理Screen的,類似於傳統的Controller,不同的Screen可以用一個Conductor來管理,Conductor也使用了策略模式允許更改對Screen的處理。
4.Coroutines,協同程序,定義了一組程序的執行,簡化了異步編程。比如說在網絡中下載圖片並顯示,通常來說需要顯示BusyIndicator,後台線程去網絡讀取圖片,讀取成功後Invoke到UI線程,取消BusyIndicator,顯示圖片。CM提供了一個IResult接口,大大的簡化了異步編程,結合ActionMessage,為AOP的擴展提供了可能。
5.配置性和擴展性,CM移除掉了原Caliburn的一些IOC實現,作為一個通用框架,最常用辦法就是使用工廠模式結合配置文件提供可配置性,使用IOC來解耦組件間的依賴。CM默認是使用MEF來做IOC擴展的,你可以自定義Bootstrapper來使用你喜歡的IOC容器,如Unity等。
6.設計時支持(Design-time support),CM中的ActionMessage是繼承自Blend中的TriggerAction的,也就是說可以在Blend編輯ActionMessage,大大方便了使用。 (這段摘抄了周永恆大大的部分對CM框架的解析,大家想詳細了解的話可以去他的博客去學習,我就不仔細說明了,以後我會用到的地方做說明)
MahApps.Metro
這是一個Metro樣式的開源項目,應用該項目可以使你的軟件具有metro的風格,具體就不多說了。
這是測試項目第一階段的運行結果
言歸正傳,我們從零開始創建項目,下面是整個測試項目的結構:
MefBootstrapper
這是啟動加載類,一般我們WPF程序是從APP.XAML裡StartupUri=“****WINDOWS.XAML”來啟動主窗體,但現在由MefBootstrapper擔當了啟動窗體的職責:
MefBootstrapper : Bootstrapper<IShell> = AggregateCatalog(AssemblySource.Instance.Select(x => batch = dockScreenManager = <IWindowManager>( WindowManager()); batch.AddExportedValue<IDockScreenManager><IEventAggregator>( GetInstance(Type serviceType, contract = .IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key; exports = container.GetExportedValues<>(contract); Exception(.Format( IEnumerable<> container.GetExportedValues<> BuildUp(
由上可知, MefBootstrapper繼承與CM框架提供Bootstrapper<TRootModel>,當Bootstrapper加載時,CM框架便會從MEF容器裡尋找出TRootModel類型的實例,並且show出來,也就是我們的主窗體,之後我會把項目源碼放出來,大家可以自己跟蹤OnStartup事件。
我們來看看APP.XMAL
<Application x:Class==== > <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary> <local:MefBootstrapper x:Key= /> </ResourceDictionary> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
IShell
一個簡單的接口,為了方便MEF導出部件
ShellView.xaml
<MetrolControls:MetroWindow x:Class===== Height= Width=> <Window.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source=/> <ResourceDictionary Source=/> <ResourceDictionary Source=/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Window.Resources> <Grid> <ContentControl x:Name= Margin= Grid.Row=/> </Grid> </MetrolControls:MetroWindow>
可以看到,這時我們引用了MahApps.Metro,MahApps.Metro自定義了一個WINDOWS,在我看來比傳統的和諧那麼一點,MahApps.Metro裡還有10多種自定義控件,有興趣的可以自己去研究
ShellViewModel
[Export( IScreen DockContent { ;
一個ShellView.xaml對應一個ShellViewModel,當ShellViewModel標記為Export時,Bootstrapper會把當前程序集所有標記為Export的類導入CM框架的IOC容器裡,ShellViewModel相當於ShellView的Datacontext,一個View的加載過程為,由Model找到(CM框架定義了各種查找規則)View,並把Model綁定到View的Datacontext,以後我們UI的邏輯代碼就可以寫在Model裡面,並與UI完全分開,這就是我們所說的MVVM模式。上面也有一個典型的View綁定Model裡的屬性,細心的可以看到:
[Import]
public IScreen DockContent { get; set; }
該屬性的名稱和ShellView.xaml裡的<ContentControl x:Name="DockContent" Margin="0,2,0,0" Grid.Row="0"/> 的命名完全一樣,奇怪的是我們並沒有寫任何綁定,但DockContent是怎麼綁定到View裡面的呢,其實綁定的過程已經由CM框架幫我們做了,CM框架會幫助我們把Model裡和控件名稱一樣的屬性綁定在一起,這就然我們省了一些事,這只是CM框架的一些小特性。
好了,主窗體的說完了,下面我們來看看怎麼把AvalonDock融合進去,上面我們說過了,一個Model對應一個View,所以我們要顯示一個UserControl時得生成一對Model-View,
DockView.xaml
<UserControl x:Class======== d:DesignWidth=> <UserControl.Resources> <avalonDock:BoolToVisibilityConverter x:Key=/> </UserControl.Resources> <Grid> <Grid x:Name=> <avalonDock:DockingManager Grid.Row= x:Name= AllowMixedOrientation= > <avalonDock:DockingManager.Theme> <avalonDock:MetroTheme/> </avalonDock:DockingManager.Theme> <avalonDock:DockingManager.LayoutItemTemplate> <DataTemplate> <ContentControl IsTabStop= /> </DataTemplate> </avalonDock:DockingManager.LayoutItemTemplate> <avalonDock:LayoutRoot> <avalonDock:LayoutPanel Orientation= > <avalonDock:LayoutAnchorablePaneGroup DockWidth= Orientation= > <avalonDock:LayoutAnchorablePane > <avalonDock:LayoutAnchorable Title= ></avalonDock:LayoutAnchorable> </avalonDock:LayoutAnchorablePane> </avalonDock:LayoutAnchorablePaneGroup> <avalonDock:LayoutPanel Orientation= > <avalonDock:LayoutDocumentPaneGroup Orientation=> <avalonDock:LayoutDocumentPane > <avalonDock:LayoutDocument Title=></avalonDock:LayoutDocument> </avalonDock:LayoutDocumentPane> </avalonDock:LayoutDocumentPaneGroup> <avalonDock:LayoutAnchorablePaneGroup DockHeight= Orientation= > <avalonDock:LayoutAnchorablePane > <avalonDock:LayoutAnchorable Title= ></avalonDock:LayoutAnchorable> </avalonDock:LayoutAnchorablePane> </avalonDock:LayoutAnchorablePaneGroup> </avalonDock:LayoutPanel> <avalonDock:LayoutAnchorablePaneGroup DockWidth= Orientation= > <avalonDock:LayoutAnchorablePane > <avalonDock:LayoutAnchorable Title= ></avalonDock:LayoutAnchorable> </avalonDock:LayoutAnchorablePane> </avalonDock:LayoutAnchorablePaneGroup> </avalonDock:LayoutPanel> </avalonDock:LayoutRoot> </avalonDock:DockingManager> </Grid> </Grid> </UserControl>
這是VS2012設計器的顯示
這些東西的學習周期還是有的,我就不一一去說。有些東西只可意會不可言傳。
DockViewModel
[Export(
我們可以看到ShellViewModel裡的DockContent就是IScreen類型的,由於標記為Import,所以程序會自動幫我們把MEF容器裡IScreen類型注入,所以其實DockContent就是DockView,我這裡為了方便直接用了CM框架的IScreen,如果有兩個類標記為[Export(typeof(IScreen))],就會導致程序異常,因為有兩個實例。程序不知道該導出哪個,所以我們之後會定義另一個接口,該接口只有唯一一個類即唯一的DockViewModel標記為導出,因為我們DockView就是唯一的,導入和導出部件這是MEF的知識,MEF是什麼大家可以百度學習,CM框架默認是MEF作為容器。
MEF
Managed Extensibility Framework(MEF)是.NET平台下的一個擴展性管理框架,它是一系列特性的集合,包括依賴注入(DI)以及Duck Typing等。MEF為開發人員提供了一個工具,讓我們可以輕松的對應用程序進行擴展並且對已有的代碼產生最小的影響,開發人員在開發過程中根據功能要求定義一些擴展點,之後擴展人員就可以使用這些擴展點與應用程序交互;同時MEF讓應用程序與擴展程序之間不產生直接的依賴,這樣也允許在多個具有同樣的擴展需求之間共享擴展程序
第一階段就先這樣,以後我會慢慢更新,直道整個插件系統的完成
如果您看了本篇博客,覺得對您有所收獲,請點擊右下角的 [推薦]
如果您想轉載本博客,請注明出處
如果您對本文有意見或者建議,歡迎留言
感謝您的閱讀,請關注我的後續博客
作者:Zengg 出處:http://www.cnblogs.com/01codeworld/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。