Wizard Framework:一個本身開發的基於Windows Forms的嚮導開發框架

最近因項目須要,我本身設計開發了一個基於Windows Forms的嚮導開發框架,目前我已經將其開源,併發布了一個NuGet安裝包。比較囧的一件事是,當我發佈了NuGet安裝包之後,發現原來已經有一個.NET的嚮導開發框架了,它叫Microsoft Visual Studio 2013 Wizard Framework。我並無對其進行深刻研究,單從名稱上看,該框架是否只能在Visual Studio 2013下使用?上網搜索過,也沒發現微軟有比較詳細的官方資料介紹這個框架。不過不管如何,我仍是在此向你們介紹一下我本身開發的這個嚮導框架,也算是讓你們瞭解一下個人設計思路,以及使你們可以方便地從該框架獲益,快捷地在本身的項目中也用上這個嚮導框架。git

有圖有真相

話很少說,請先看效果圖。爲了演示這個框架,我依賴它開發了一個模擬軟件安裝過程的嚮導程序。用過相似Install Shield的安裝程序的用戶,應該對下面的這些對話框比較熟悉吧:github

image

image

image

怎麼樣?看上去還算專業吧?它就是用Wizard Framework開發的。1.0.0版本支持如下功能:併發

  • 嚮導對話框能夠定製,好比能夠自定義對話框的尺寸、Icon、是否支持在線幫助等等
  • 由Windows Forms設計器支持的嚮導頁面設計,開發人員能夠像開發一個用戶控件同樣,直接在Visual Studio中使用拖拽的方式,設計每一個頁面的界面
  • 每一個頁面均可以經過CanGoPreviousPage、CanGoNextPage、CanGoFinishPage以及CanGoCancel四個屬性,直接設置嚮導對話框中「上一步」、「下一步」、「完成」和「取消」按鈕的狀態
  • 每一個頁面均可以讀取其它任何頁面所保存的嚮導模型(WizardModel),經過嚮導模型獲取各個頁面的設置參數(好比上面「安裝信息彙總」頁面中就讀取了「軟件功能選擇」頁面的數據並顯示出來)
  • 每一個頁面均可以直接設定其它頁面是否在上一步或者下一步可見,好比,在有些狀況下,噹噹前頁的某個參數被設置後,咱們但願在點「下一步」的時候,可以跳過下一頁,而直接進入下下頁
  • 每一個頁面均可以設置本身的Logo
  • 對C# 5.0中async/await的支持,使得面向嚮導的異步開發模型變得異常簡單
  • 支持中文和英文

那麼,我該如何得到源代碼或者開發包呢?框架

源代碼與NuGet安裝包

你能夠直接訪問Wizard Framework的主頁:https://github.com/daxnet/wizard-framework。若是你裝有Git客戶端的話,能夠將本項目克隆到本地:異步

git clone https://github.com/daxnet/wizard-framework

等克隆結束後,直接在Visual Studio 2013中打開WizardFramework.sln便可(目前Wizard Framework基於.NET Framework 4.5.1開發,因此建議仍是用Visual Studio 2013打開)。此時,你能夠看到該解決方案包含兩個項目:async

image

WizardFramework項目就是該框架的源代碼,而InstallerSample是一個Windows Forms應用程序,它使用了WizardFramework開發了一個模擬軟件安裝過程的嚮導界面,也就是上面你所看到的界面效果了。你能夠修改Program.cs中Main函數的第一條語句,將本地化信息設置爲zh-CN或者en-US,來體驗該模擬程序在不一樣區域語言下的界面效果。編輯器

若是你但願在本身的Windows Forms項目中使用Wizard Framework,你能夠在項目上單擊鼠標右鍵,選擇Manage NuGet Packages菜單項,在彈出的對話框中搜索WizardFramework關鍵字便可:ide

image

選中以後,單擊「安裝」按鈕,便可將本嚮導開發框架添加到你的項目中(注意:建議應用程序是基於.NET Framework 4.5.1開發的)。函數

使用方法

經過NuGet Package Manager添加了Wizard Framework的引用以後,就能夠開始開發嚮導應用了。基本上能夠分三個步驟:開發嚮導頁、開發嚮導對話框,以及將嚮導頁添加到嚮導對話框。ui

開發嚮導頁

要開發一個嚮導頁,只需在Visual Studio的Windows Forms項目上,添加一個用戶控件(UserControl),而後使其繼承於WizardFramework.WizardPage類便可。此時,Visual Studio編輯器會提示構造函數錯誤,由於WizardPage類型沒有可訪問的默認構造函數,這就須要經過自定義的嚮導頁類的構造函數向基類傳入參數。如下是WizardPage構造函數的重載,以及各重載構造函數的參數描述。

  • WizardPage(string title, string description, Wizard wizard, IWizardModel model = null)
    • title:用於顯示在每一個嚮導頁上方黑體標題部分的標題信息
    • description:用於顯示在每一個嚮導頁上方的嚮導頁描述信息
    • wizard:當前嚮導頁所在的嚮導對象,通常經過嚮導頁的構造函數參數傳入
    • model:當前嚮導頁所使用的數據對象模型
  • WizardPage(string title, string description, Wizard wizard, WizardPageType type)
    • title:用於顯示在每一個嚮導頁上方黑體標題部分的標題信息
    • description:用於顯示在每一個嚮導頁上方的嚮導頁描述信息
    • wizard:當前嚮導頁所在的嚮導對象,通常經過嚮導頁的構造函數參數傳入
    • type:當前嚮導頁的類型。分爲兩種類型:Standard和Expanded。Standard類型的意思是,當顯示該向導頁時,會在嚮導對話框的上方顯示title和description信息;而對於Expanded類型,則這部分信息不會顯示出來,整個頁面的設計徹底由開發人員本身控制。顯然,在上面的示例中,二、三、四、5頁都是屬於Standard類型的嚮導頁,而1和6頁則屬於Expanded類型
  • WizardPage(string title, string description, Wizard wizard, IWizardModel model, WizardPageType type)
    • title:用於顯示在每一個嚮導頁上方黑體標題部分的標題信息
    • description:用於顯示在每一個嚮導頁上方的嚮導頁描述信息
    • wizard:當前嚮導頁所在的嚮導對象,通常經過嚮導頁的構造函數參數傳入
    • model:當前嚮導頁所使用的數據對象模型
    • type:當前嚮導頁的類型。分爲兩種類型:Standard和Expanded。Standard類型的意思是,當顯示該向導頁時,會在嚮導對話框的上方顯示title和description信息;而對於Expanded類型,則這部分信息不會顯示出來,整個頁面的設計徹底由開發人員本身控制。顯然,在上面的示例中,二、三、四、5頁都是屬於Standard類型的嚮導頁,而1和6頁則屬於Expanded類型

如下是一個嚮導頁的類定義以及構造函數的實現例子:

public partial class FirstPage : WizardPage
{
    public FirstPage(Wizard wizard)
        :base("First Page", "This is the first page.", wizard)
    {
        InitializeComponent();
    }
}

須要注意的是,嚮導頁的構造函數必須是公有(public)的,並且有且只有一個Wizard類型的參數。

嚮導頁中的幾個回調函數

在WizardFramework.WizardPage基類中,定義了一些可供Wizard對象調用的回調函數,這些函數將在適當的時候被調用,所以,開發人員能夠在這些回調函數中處理本身的邏輯,好比設置是否容許用戶點擊「下一頁」等導航按鈕。

  • 【方法】Task ExecuteShowAsync(IWizardPage fromPage)
    • 當Wizard準備顯示當前嚮導頁時,調用此方法。該方法以異步方式調用
    • fromPage參數:表示是從哪一個嚮導頁導航過來的。好比,當用戶點擊「下一頁」按鈕後,下一個嚮導頁將會顯示在嚮導對話框中,一般狀況下,fromPage參數是所顯示的嚮導頁的上一頁
  • 【方法】Task<bool> ExecuteBeforeGoingPreviousAsync()
    • 當用戶點擊「上一頁」按鈕後,嚮導對話框準備進入上一貫導頁時,調用此方法。該方法以異步方式調用
    • 返回值:返回一個可以返回布爾值的任務對象,此布爾值表示是否真的容許嚮導對話框進入上一頁(True=容許;False=不容許)
  • 【方法】Task<bool> ExecuteBeforeGoingNextAsync()
    • 當用戶點擊「下一頁」按鈕後,嚮導對話框準備進入下一貫導頁時,調用此方法。該方法以異步方式調用
    • 返回值:返回一個可以返回布爾值的任務對象,此布爾值表示是否真的容許嚮導對話框進入下一頁(True=容許;False=不容許)
  • 【方法】Task<bool> ExecuteBeforeGoingFinishAsync()
    • 當用戶點擊「完成」按鈕後,嚮導對話框準備進入「完成」嚮導頁時,調用此方法。該方法以異步方式調用
    • 返回值:返回一個可以返回布爾值的任務對象,此布爾值表示是否真的容許嚮導對話框結束,並向調用方返回DialogResult.OK值(True=容許;False=不容許)
  • 【方法】void PersistValuesToModel()
    • 當嚮導對話框準備進入其它嚮導頁時,會調用此方法,將當前已顯示的嚮導頁界面上的用戶設置保存到嚮導數據模型對象中,下一節將詳細介紹這部份內容
  • 【屬性】System.Windows.Forms.Control FocusingControl
    • 設置在打開當前嚮導頁時,焦點(Focus)所在的界面控件(即焦點默認應該在哪一個控件上)
  • 【屬性】System.Drawing.Image Logo
    • 設置當前嚮導頁須要顯示在嚮導對話框右上角的圖標

開發人員在自定義本身的嚮導頁面時,能夠在子類中重載以上方法或屬性,以在不一樣的時機處理不一樣的邏輯。詳細使用方法,能夠參考WizardFramework源代碼庫自帶的InstallerSample示例項目。

嚮導數據模型

在WizardFramework中,經過引入嚮導數據模型的概念,來保存每一個嚮導頁的用戶設置。好比,在InstallerSample示例項目的FeaturePage嚮導頁中,用戶能夠在界面上選擇安裝的類型(最小安裝、標準安裝和徹底安裝),還能夠指定安裝路徑。這些用戶設定都被保存在該向導頁的數據模型中,以便其它嚮導頁或者嚮導對話框讀取使用。嚮導數據模型類的定義,須要實現IWizardModel接口,以下:

public sealed new class Model : IWizardModel
{
    #region Public Properties

    public string SelectedFeature { get; set; }

    public string SelectedFolder { get; set; }

    #endregion Public Properties

    #region Public Methods

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine(string.Format(Resources.SelectedFeaturePattern, SelectedFeature));
        sb.AppendLine(string.Format(Resources.InstallationFolderPattern, SelectedFolder));
        return sb.ToString();
    }

    #endregion Public Methods
}

在數據模型對象中,只須要編寫一些與界面控件取值相對應的屬性便可。一種推薦的作法是,將嚮導數據模型類定義在每一個嚮導頁的類定義中,也就是做爲嚮導頁類的一個內嵌類來定義,類名就簡單地使用Model做爲類名就好了,爲了繞過編譯器警告,在聲明類的時候加上new關鍵字。這樣作的好處是,從此在其它嚮導頁面或者嚮導對話框中獲取嚮導模型對象時,有助於提升代碼的可讀性。

若是嚮導頁須要使用嚮導數據模型,則須要在構造函數中初始化數據模型對象,以下(注意base構造函數調用的最後一個參數):

public FeaturePage(Wizard wizard)
    : base(Resources.FeaturePageTitle, Resources.FeaturePageDescription, wizard, new Model())
{
    InitializeComponent();
}

而且,須要重載PersistValuesToModel方法,以便將界面控件的值保存到數據模型中:

protected override void PersistValuesToModel()
{
    var selectedFeature = string.Empty;
    if (rbMinimal.Checked)
        selectedFeature = rbMinimal.Text;
    else if (rbStandard.Checked)
        selectedFeature = rbStandard.Text;
    else if (rbFull.Checked)
        selectedFeature = rbFull.Text;

    ModelAs<Model>().SelectedFeature = selectedFeature;
    ModelAs<Model>().SelectedFolder = txtInstPath.Text;
}

當須要在其它頁面中,或者經過嚮導對話框獲取嚮導頁的數據模型對象時,可使用下面的方法:

var model = Wizard.GetWizardModel<FeaturePage.Model>();

此處,經過Wizard對象的GetWizardModel泛型方法,便可獲得FeaturePage.Model數據模型對象。

控制嚮導的導航

在有些場景下,須要根據當前頁的某些界面設置,來決定下一頁應該導航到哪一個嚮導頁。好比,在嚮導頁1中,若是用戶點擊了某個複選框,那麼當用戶再點「下一步」按鈕時,則跳過頁面2,直接進入頁面3,不然,則須要跳到頁面2。此時,能夠調用Wizard對象的SetPageDisplay方法便可。該方法有兩個重載:

  • void SetPageDisplay(int pageIndex, WizardPageDisplay display)
    • pageIndex:根據嚮導頁加入到嚮導對話框的順序,所對應的嚮導頁索引號
    • display:指定該頁是顯示(WizardPageDisplay.Show)仍是不顯示(WizardPageDisplay.Hide)
  • void SetPageDisplay<T>(WizardPageDisplay display)
    • 泛型類型T:指定須要設置顯示行爲的嚮導頁類型
    • display:指定該頁是顯示(WizardPageDisplay.Show)仍是不顯示(WizardPageDisplay.Hide)

開發嚮導對話框

嚮導對話框的開發很是簡單,只須要新建一個System.Windows.Forms.Form類型,而後使其繼承於WizardFramework.Wizard類便可,無需再寫更多的代碼。固然,若是須要設置一些額外的屬性,也能夠直接在Visual Studio的屬性頁中進行設置便可。

初始化嚮導頁,並將嚮導頁添加到嚮導對話框中

下面的代碼展現了嚮導頁初始化並添加到嚮導對話框的作法,仍是很是簡單的:

var installer = new FrmInstaller();
installer.Add(installer.CreatePage<WelcomePage>());
installer.Add(installer.CreatePage<LicensePage>());
installer.Add(installer.CreatePage<FeaturePage>());
installer.Add(installer.CreatePage<SummaryPage>());
installer.Add(installer.CreatePage<InstallingPage>());
installer.Add(installer.CreatePage<FinishPage>());

總結

本文介紹了我本身開發的一個嚮導框架,並介紹了框架的使用。或許,在某些狀況下,該框架仍是不能知足需求,此時,能夠直接把WizardFramework的源代碼拉下來進行定製。

相關文章
相關標籤/搜索