最近因项目需要,我自己设计开发了一个基于Windows Forms的向导开发框架,目前我已经将其开源,并发布了一个NuGet安装包。比较囧的一件事是,当我发布了NuGet安装包以后,发现原来已经有一个.NET的向导开发框架了,它叫Microsoft Visual Studio 2013 Wizard Framework。我并没有对其进行深入研究,单从名称上看,该框架是否只能在Visual Studio 2013下使用?上网搜索过,也没发现微软有比较详细的官方资料介绍这个框架。不过无论如何,我还是在此向大家介绍一下我自己开发的这个向导框架,也算是让大家了解一下我的设计思路,以及使大家能够方便地从该框架获益,快捷地在自己的项目中也用上这个向导框架。
话不多说,请先看效果图。为了演示这个框架,我依赖它开发了一个模拟软件安装过程的向导程序。用过类似Install Shield的安装程序的用户,应该对下面的这些对话框比较熟悉吧:
怎么样?看上去还算专业吧?它就是用Wizard Framework开发的。1.0.0版本支持以下功能:
那么,我该如何获得源代码或者开发包呢?
你可以直接访问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打开)。此时,你可以看到该解决方案包含两个项目:
WizardFramework项目就是该框架的源代码,而InstallerSample是一个Windows Forms应用程序,它使用了WizardFramework开发了一个模拟软件安装过程的向导界面,也就是上面你所看到的界面效果了。你可以修改Program.cs中Main函数的第一条语句,将本地化信息设置为zh-CN或者en-US,来体验该模拟程序在不同区域语言下的界面效果。
如果你希望在自己的Windows Forms项目中使用Wizard Framework,你可以在项目上单击鼠标右键,选择Manage NuGet Packages菜单项,在弹出的对话框中搜索WizardFramework关键字即可:
选中之后,单击“安装”按钮,即可将本向导开发框架添加到你的项目中(注意:建议应用程序是基于.NET Framework 4.5.1开发的)。
通过NuGet Package Manager添加了Wizard Framework的引用之后,就可以开始开发向导应用了。基本上可以分三个步骤:开发向导页、开发向导对话框,以及将向导页添加到向导对话框。
要开发一个向导页,只需在Visual Studio的Windows Forms项目上,添加一个用户控件(UserControl),然后使其继承于WizardFramework.WizardPage类即可。此时,Visual Studio编辑器会提示构造函数错误,因为WizardPage类型没有可访问的默认构造函数,这就需要通过自定义的向导页类的构造函数向基类传入参数。以下是WizardPage构造函数的重载,以及各重载构造函数的参数描述。
以下是一个向导页的类定义以及构造函数的实现例子:
public partial class FirstPage : WizardPage { public FirstPage(Wizard wizard) :base("First Page", "This is the first page.", wizard) { InitializeComponent(); } }
需要注意的是,向导页的构造函数必须是公有(public)的,而且有且只有一个Wizard类型的参数。
在WizardFramework.WizardPage基类中,定义了一些可供Wizard对象调用的回调函数,这些函数将在适当的时候被调用,因此,开发人员可以在这些回调函数中处理自己的逻辑,比如设置是否允许用户点击“下一页”等导航按钮。
开发人员在自定义自己的向导页面时,可以在子类中重载以上方法或属性,以在不同的时机处理不同的逻辑。详细使用方法,可以参考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方法即可。该方法有两个重载:
向导对话框的开发非常简单,只需要新建一个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的源代码拉下来进行定制。