Prism - 第一個!超簡單Prism範例

18 March 2012 — Written by Sky Chang
#Silveright#WPF

這篇的內容,主要是翻譯於這個網站的內容,是由國外的Nick Polyak高手所寫的,然後再加上小弟雜多的解釋內容XDD,所以內容不是百分百和原網站一樣,而且差異甚大,如有不好之處,也請各位多多包涵 ( 所以這篇可以算是讀後心得了,不算翻譯文了.. )

最簡單的Prism程式

這裡示範的第一個最簡單的Prism程式,為什麼叫做最簡單呢!?因為這個範例裡面完全沒有任何的視覺效果,也就是說,不會放一些啥Button等等之類的Control,只有最簡單的東西,運作出來的結果如下,我們可以看到畫面非常的單純, 單純到沒有任何東西XDD。

image

雖然一片空白,但裡面有很多學問=w=,接下來,我們看看怎樣來做這個範例。

實作Main Project

首先我們先建立一個Silverlight應用程式,並且把不需要的東西先刪除掉,這裡我們把MainPage.xaml刪除掉,所以目前專案架構會變成如下圖;因為這個範例我們沒有打算使用到視覺的部分,只是單純的希望能了解他的架構,所以我們用不到MainPage.xaml,就先刪除掉吧。

image

這邊我們需要參考兩個dll,這兩個dll分別在安裝Prism的bin目錄下面,分別是Microsoft.Practices.Prism.dll和Microsoft.Practies.Prism.MefExtension.dll。

image

接下來,我們要改變一下App.xaml.cs的程式碼,位置如下圖。

image

我們打開App.xaml.cs的程式碼,會發現裡面有錯誤;這是很正常的,因為我們已經把MainPage.xaml砍掉了,所以我們要改變一下這邊的程式碼。

image

修改App.xaml.cs的Application_Startup

改成如下;打的時候會發現TheBootstrapper找不到,不過那是正常的,因為這個Class我們還沒撰寫,我們這邊改用TheBootstrapper來取代原本程式執行時預設顯示的View,如果是原本程式架構,當程式執行時,會將MainPage.xaml給實例化起來,並且變成預設的根畫面( RootVisual,也就是最底層的畫面 ),但我們使用Prism時,不會使用原本的MainPage.xaml ( 無論是不是這簡單的範例都一樣,都會改變這行);因為使用Prism的時候,需要的東西和原本預設的MainPage.xaml是完全不一樣的,所以改用Prism時,我們會使用自己建立的Bootstrapper Class來產生整個Prism所需要的東西,而這裡我們自己建立的Bootstrapper Class稱為TheBootstrapper。

private void Application_Startup(object sender, StartupEventArgs e)
{
    (new TheBootstrapper()).Run();
}

撰寫Bootstrapper Class

接下來,我要要建立一個TheBootstrapper.cs類別,內容如下;這個Class將替我們產生Prism所需要的Shell( 也就最上層的View )和整個底層的組件,Bootstrapper也會註冊一些需要用到的服務( 這裡使用MEF,所以必須繼承於MefBootstrapper )。

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Practices.Prism.MefExtensions;
using Microsoft.Practices.Prism.Modularity;

namespace PrismDeom1NoVirual
{
    public class TheBootstrapper : MefBootstrapper
    {
        protected override void InitializeShell()
        {
            base.InitializeShell();

            // 這裡是給Silverlight用,如果是WPF會不一樣。
            Application.Current.RootVisual = (UIElement)Shell;
        }

        // 建立Shell的方法,shell在Prism Application是主要的View 
        // 在這個範例,我們只想了解BootStrapper,所以我們把原本的MainPage刪掉。
        // 並且利用Grid當作主要的Shell
        protected override DependencyObject CreateShell()
        {
            return new Grid();
        }

        protected override IModuleCatalog CreateModuleCatalog()
        {
            ModuleCatalog moduleCatalog = new ModuleCatalog();

            //在這邊,我們使用moduleCatalog來加載模組進來。
            moduleCatalog.AddModule
            (
                new ModuleInfo
                {
                    InitializationMode = InitializationMode.WhenAvailable,
                    Ref = "Module1.xap",
                    ModuleName = "Module1Impl",
                    ModuleType = "Module1.Module1Impl, Module1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                }
            );

            return moduleCatalog;
        }
    }
}

在這邊,需要注意到這個Class執行Function的一個順序性( 未來會有一篇來探討原始碼 ),我們接下來看看這順序性是如何,我們這個Bootstrapper只有Override三個Function,你會發現他最先執行的Function是CreateModuleCatalog(),也就是說,他會先建立moduleCatalog這個Class,這個Class的用途是紀錄目前有哪些module,並準備利用MEF的方式去做個組合,寫法就如上面的程式碼一樣( 等下會去建立Module );第二個執行的Function是CreateShell(),我們把原本在ApplicationStartup方法裡面建立View的任務,移到這裡來,而這邊,我們直接new一個Grid,畢竟原本的MainPage.xaml被我們刪除掉了;第三個要執行的Function是InitializeShell(),除了原本MEFBootstrapper原本就該執行的程式外,我們也把ApplicationStratup指定RootVisual的任務,寫在這邊;或許有人會問說,為什麼我會知道順序!?其實很簡單,因為我翻過原始碼…

建立Module Project

緊接著,我們要來建立Module,在Prism裡面,通常會把Module建立成獨立的專案來進行,所以我們建立一個新的專案,這邊要特別注意,要選擇的是Silverlight應用程式( Silverlight Application )而非Silverlight類別庫 ( Silverlight Class ),這是因為Module是一個xap,而非dll。

image

接下來,我們不需要額外的測試頁,所以把測試頁的勾選拿掉。

image

建立完新的專案後,把APP.xaml和MainPage.xaml刪除到( 這是因為我們這個範例沒用到 ),刪除完後,並建立一個Class,名稱取為Module1Impl.cs,完成後如下。

image

接下來,又要參照一些dll了,除了上面的那兩個dll要參照進來,還需要參照.NET Framework內建的System.ComponentModel.Composition。這裡因為我是使用Silverlight 5,所以使用5.0版本。

image

參照完後,在Module Project的地方,需要特別注意,我們要把參照到的Microsoft.Practices.Prism和Microsoft.Practies.Prism.MefExtension,複製到本機的選項改為False,這點要特別注意,如果設定為True,程式還是可以跑,也不會報錯,但就是不會加載Module進來 ( 只需要改Module的專案。 )。

image

撰寫Module1 Class

接下來,我們要撰寫Module,Module必須實作於IModule,而這邊會使用ModuleExport屬性來標記,讓Prism知道這是一個Module。

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.MefExtensions.Modularity;

namespace Module1
{
    //利用ModuleExport屬性來標記,這是一個Module
    [ModuleExport(typeof(Module1Impl))]
    public class Module1Impl : IModule
    {

        #region IModule Members

        public void Initialize()
        {

        }

        #endregion
    }
}

最後,我們可以設定中斷點在這邊,當程式執行的時候,如果有進到這個中斷點,就表示有順利的去加載這個Module了。

image

後記

做到這邊,最簡單的Prism程式就完成了,在Prism裡面,如果用的是MEF框架,那建議先稍微懂一下MEF會比較好,不然做下來可能會湖煞煞,如果有時間,也建議把IoC的部分有個理解,因為有很多地方,都是利用注入的概念;其實Prism就如許多前輩講的一樣,學習門檻真比較高,光是這邊文章,打打停停,也打了三天,而且其實還有很多東西還沒講得很仔細,這部分未來會再慢慢補充回來,如果覺得很有趣,迫不急待的人,也可以先看參考資料,繼續下去=w=。

參考資料

Sky & Study4.TW