Prism是由微軟Patterns & Practices團隊開發的項目,目的在於幫助開發人員構建鬆散耦合的、更靈活、更易於維護並且更易於測試的WPF應用或是Silverlight應用以及Windows Phone 7應用。使用Prism可以使程序開發更趨於模塊化,整個項目將由多個離散的、鬆耦合的模塊組成,而各個模塊又可以又不同的開發者或團隊進行開發、測試和部署。目前Prism的最新版本是Prism 4,於2010年11月12日發佈。Prism有很完整的文檔以及豐富的示例程序。在這裏我們僅針對於Silverlight程序的開發。
在下載Prism安裝包並安裝完成後,會在目標文件夾中發現很多文件。
推薦首先運行RegisterPrismBinaries.bat文件,這樣在開發基於Prism的程序時可以更方便地添加引用程序集。
使用Prism之前,需要了解一些概念,下面通過一個非常簡單的小程序來了解一下Prism。
1.打開Visual Studio 2010,新建一個Silverlight Application項目,並添加對Prism的引用。再創建三個Silverlight類庫工程。
2.在Contract工程下新建一個接口,叫做ITextProvider。
1
2
3
4
|
public interface ITextProvider { string GetText(); } |
3.在其它的三個項目中都引用Contract項目。
4.在PrismStarter工程下新建一個TextProvider類並實現ITextProvider接口。
1
2
3
4
5
6
7
8
9
10
|
public class TextProvider
: ITextProvider { private int i
= 0; public string GetText() { i++; return string .Format( "From
TextProvider [{0}]" ,
i); } } |
5.刪除PrismStarter項目中自動生成的MainPage.xaml,創建一個新的UserControl,叫做Shell。頁面代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
< UserControl x:Class="PrismStarter.Shell" xmlns:prism="http://www.codeplex.com/prism" mc:Ignorable="d" d:DesignHeight="300"
d:DesignWidth="400"> < Grid x:Name="LayoutRoot"
Background="White"> < Grid.RowDefinitions > < RowDefinition Height="100"
/> < RowDefinition Height="100"
/> < RowDefinition Height="100"
/> </ Grid.RowDefinitions > < TextBlock FontSize="30"
VerticalAlignment="Center" HorizontalAlignment="Center" Text="Prism Starter" /> < ContentControl Grid.Row="1"
HorizontalContentAlignment="Stretch" prism:RegionManager.RegionName="RegionA" /> < ContentControl Grid.Row="2"
HorizontalContentAlignment="Stretch" prism:RegionManager.RegionName="RegionB" /> </ Grid > </ UserControl > |
6.在ModuleA工程中添加對Prism程序集的引用。並添加一個UserControl叫做ViewA,頁面代碼爲:
1
2
3
|
< Grid x:Name="LayoutRoot"
Background="White"> < TextBlock x:Name="textModuleA"
FontSize="30" VerticalAlignment="Center" HorizontalAlignment="Center" /> </ Grid > |
CodeBehind中的代碼爲:
1
2
3
4
5
6
7
8
9
10
11
12
|
public partial class ViewA
: UserControl { public ViewA(ITextProvider
textProvider) { InitializeComponent(); this .Loaded
+= (s, e) => { textModuleA.Text
= string .Format( "Module
A {0}" ,
textProvider.GetText()); }; } } |
7.在ModuleA工程中添加一個類叫做ModuleA,並實現接口IModule。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class ModuleA
: IModule { private IRegionManager
_regionManager; public ModuleA(IRegionManager
regionManager) { _regionManager
= regionManager; } public void Initialize() { _regionManager.RegisterViewWithRegion( "RegionA" ,
typeof (ViewA)); } } |
注意這裏的RegionA對應於Shell頁面中的RegionName。
8.在ModuleB工程中重複6、7過程,只是將A替換爲B。
9.在PrismStarter工程中添加對ModuleA和ModuleB的引用。
10.在PrismStarter工程中添加一個PrismStarterBootstrapper類,並繼承UnityBootstrapper。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public class PrismStarterBootstrapper
: UnityBootstrapper { protected override DependencyObject
CreateShell() { return this .Container.TryResolve<Shell>(); } protected override void InitializeShell() {
//
控制頁面在初始化時顯示Shell頁面 App.Current.RootVisual
= (UIElement) this .Shell; } protected override void ConfigureModuleCatalog() {
//
註冊Module。在實際開發中可以使用xaml做配置文件, //
這樣就可以將PrismStarter與ModuleA和ModuleB完全解耦,也就不再需要引用這兩個項目 Type
moduleAType = typeof (ModuleA.ModuleA); ModuleInfo
moduleA = new ModuleInfo { ModuleName
= moduleAType.Name, ModuleType
= moduleAType.AssemblyQualifiedName, }; Type
moduleBType = typeof (ModuleB.ModuleB); ModuleInfo
moduleB = new ModuleInfo { ModuleName
= moduleBType.Name, ModuleType
= moduleBType.AssemblyQualifiedName, }; this .ModuleCatalog.AddModule(moduleA); this .ModuleCatalog.AddModule(moduleB); } protected override void ConfigureContainer() {
//
註冊一下TextProvider,這樣在通過容器請求ITextProvider時會返回TextProvider實例 base .ConfigureContainer(); this .Container.RegisterInstance<ITextProvider>( new TextProvider()); } } |
11.最後一步,打開App.xaml.cs,修改Application_Startup方法
1
2
3
4
5
|
private void Application_Startup( object sender,
StartupEventArgs e) { PrismStarterBootstrapper
bootstrapper = new PrismStarterBootstrapper(); bootstrapper.Run(); } |
運行程序,結果如下:
下面簡單介紹一下這個小例子中涉及到的一些概念。
Bootstrapper: 在程序中使用框架需要找到一個切入點,將框架植入進去,將一部分功能委託給框架來實現。在Silverlight中使用Prism的切入點就是App.xaml.cs中的Application_Startup方法。一般來說,這個方法中只是指定頁面最先加載的頁面,但是我們把默認的邏輯去掉,取而代之的是Bootstrapper(在本例中就是PrismStarterBootstrapper)。當調用Bootstrapper.Run方法時,它會完成一些準備工作,如一些配置等。因此你會發現,使用Prism後,啓動程序時會比正常啓動要慢一些,就是因爲Bootstrapper做了許多工作。
Container: 依賴注入容器。在程序中使用依賴注入的好處到處都可以找的到。在Silverlight中使用容器來管理各個組件的一個很明顯的好處就是使用單例來降低內存使用。否則每次加載一個頁面都需要重新創建一個也很耗費資源的。當然好處不只這些,通過容器來注入一些服務(如本例中的IRegionManager和ITextProvider)顯得相當方便。
Module: Prism幫助我們把程序分解成一個個功能模塊,這些功能模塊就叫做Module,通常一個工程就是一個Module。由於Module彼此是獨立的,但是在運行時需要將它們整合到一起,因此Prism需要知道Module的存在,這裏就涉及到了ModuleCatalog, ModuleCatalog就是Module的容器,裏面包含了所有Module的信息,以ModuleInfo的形式存在。ModuleInfo就是對Module的抽象,包含Module的名字,類型,依賴等一些信息。
Shell: 相當於程序的入口,初始界面,還能夠提供類似ASP.Net中的母版頁的功能。Shell必須由Bootstrapper創建,因爲Shell需要使用的一些service,比如RegionManager等,需要在Shell顯示前註冊。
Region: 相當於ASP.Net中的ContentPlaceHolder(是這麼叫的吧?),起到佔位符的作用,如本例中Shell中有兩個Region——RegionA和RegionB,定義了兩塊區域。在Module的初始化過程中,通過IRegionManager將Module中的頁面放進了定義好的Region中。IRegionManager負責管理Region,可以通過它向Region中註冊View,進行導航等。
Prism的功能當然遠不止這麼簡單,它還提供對MVVM模式的支持,對導航的支持等,在後續文章中會逐步介紹。希望能夠通過本文讓大家對Prism有一定的瞭解。