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的源代码拉下来进行定制。

相关文章
相关标签/搜索