Wizard Framework:一个自己开发的基于Windows Forms的向导开发框架
最近因项目需要,我自己设计开发了一个基于Windows Forms的向导开发框架,目前我已经将其开源,并发布了一个NuGet安装包。比较囧的一件事是,当我发布了NuGet安装包以后,发现原来已经有一个.NET的向导开发框架了,它叫Microsoft Visual Studio 2013 Wizard Framework。我并没有对其进行深入研究,单从名称上看,该框架是否只能在Visual Studio 2013下使用?上网搜索过,也没发现微软有比较详细的官方资料介绍这个框架。不过无论如何,我还是在此向大家介绍一下我自己开发的这个向导框架,也算是让大家了解一下我的设计思路,以及使大家能够方便地从该框架获益,快捷地在自己的项目中也用上这个向导框架。
有图有真相
话不多说,请先看效果图。为了演示这个框架,我依赖它开发了一个模拟软件安装过程的向导程序。用过类似Install Shield的安装程序的用户,应该对下面的这些对话框比较熟悉吧:
怎么样?看上去还算专业吧?它就是用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打开)。此时,你可以看到该解决方案包含两个项目:
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构造函数的重载,以及各重载构造函数的参数描述。
- 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类型,则这部分信息不会显示出来,整个页面的设计完全由开发人员自己控制。显然,在上面的示例中,2、3、4、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类型,则这部分信息不会显示出来,整个页面的设计完全由开发人员自己控制。显然,在上面的示例中,2、3、4、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的源代码拉下来进行定制。
Wizard Framework:一个自己开发的基于Windows Forms的向导开发框架的更多相关文章
- 团队软件开发_基于windows下截屏软件关于NABC框架的特点
经过我们小组数次的激烈讨论,就自己的能力和时间而言,我们小组的初步的计划是开发一款基于windows下的截图软件. 关于这个软件的功能,我们初步的想法如下: 1.能在windows下后台运行,有相应的 ...
- Windows Forms (一)
导读 1.什么是 Windows Forms 2.需要学Windows Forms 么? 3.如何手写一个简单的Windows Forms 程序 4.对上面程序的说明 5.Form 类与Control ...
- 构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)
通过前面几节的准备工作,对于 npm / node / gulp 应该已经有了基本的认识,本节主要介绍如何构建一个基本的前端自动化开发环境. 下面将逐步构建一个可以自动编译 sass 文件.压缩 ja ...
- 基于windows环境VsCode的ESP32开发环境搭建
1. 基于windows环境VsCode的ESP32开发环境搭建,网上有各类教程,但是我实测却不行. 例如我在vscode内安装的乐鑫插件,扩展配置项是下图这样: 而百度的各类博文却都是这样: 经过网 ...
- 【Kafka】基于Windows环境的Kafka有关环境(scala+zookeeper+kafka+可视化工具)搭建、以及使用.NET环境开发的案例代码与演示
前言:基于Windows系统下的Kafka环境搭建:以及使用.NET 6环境进行开发简单的生产者与消费者的演示. 一.环境部署 Kafka是使用Java语言和Scala语言开发的,所以需要有对应的Ja ...
- 【Hades】ades是一个开源库,基于JPA和Spring构建,通过减少开发工作量显著的改进了数据访问层的实现
几乎每个应用系统都需要通过访问数据来完成工作.要想使用领域设计方法,你就需要为实体类定义和构建资源库来实现领域对象的持久化.目前开发人员经常使用JPA来实现持久化库.JPA让持久化变得非常容易,但是仍 ...
- RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue )协议的开源实现。
RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue )协议的开源实现. 1. 介绍 RabbitMQ是一个由erlang开发的基于AMQP(Advan ...
- 一个基于 .NET Core 2.0 开发的简单易用的快速开发框架 - LinFx
LinFx 一个基于 .NET Core 2.0 开发的简单易用的快速开发框架,遵循领域驱动设计(DDD)规范约束,提供实现事件驱动.事件回溯.响应式等特性的基础设施.让开发者享受到正真意义的面向对象 ...
- 基于vuecli3构建一个快速开发h5 APP的模板
基于vuecli3构建的一个快速开发h5 APP的模板,集成了高德地图.mint-ui,以及antv-f2可视化框架 vue-cli3安装 查看vue cli版本 vue --version 要求no ...
随机推荐
- 2D、3D形变
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 17.0px Monaco; color: #a5b2b9 } span.Apple-tab-span { ...
- 谈谈一些有趣的CSS题目(十)-- 结构性伪类选择器
开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...
- AFNetworking 3.0 源码解读(九)之 AFNetworkActivityIndicatorManager
让我们的APP像艺术品一样优雅,开发工程师更像是一名匠人,不仅需要精湛的技艺,而且要有一颗匠心. 前言 AFNetworkActivityIndicatorManager 是对状态栏中网络激活那个小控 ...
- 小兔JS教程(三)-- 彻底攻略JS回调函数
这一讲来谈谈回调函数. 其实一句话就能概括这个东西: 回调函数就是把一个函数当做参数,传入另一个函数中.传进去的目的仅仅是为了在某个时刻去执行它. 如果不执行,那么你传一个函数进去干嘛呢? 就比如说对 ...
- springmvc SSM shiro redis 后台框架 多数据源 代码生成器
A集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单 下载地址 ; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类 ...
- Linux网卡驱动安装、防火墙原理
安装网卡驱动程序: 需要检查是否安装kernel依赖包: rpm –q kernel-devel #检查kernel依赖包是否安装 yum –y install kernel-devel 检查gcc和 ...
- 烂泥:wiki系统confluence5.6.6安装、中文、破解及迁移
本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb confluence是一个专业的企业知识管理与协同软件,可以用于构建企业wiki.通过它 ...
- FineReport如何部署Tomcat服务器集群
环境准备 Tomcat服务器集群中需要进行环境准备: Apache:Apache是http服务器,利用其对Tomcat进行负载均衡,这里使用的版本是Apache HTTP Server2.0.64: ...
- 【每日一linux命令2】命令执行顺序:
二.命令顺序: 若在 shell 内置的命令/bin 以及/usr/bin 之下都出现了命令 pwd,那当我们执行该命令时,会执行哪 一个?答案是第一优先执行 shell 内置的命令,再执行路 ...
- NYOJ 455
1.应该交代清楚,参加宴会的人不知道一共有多少顶帽子.假如知道有n顶帽子的话,第一次开灯看见有n-1只,自然就知道自己是第n顶黑帽子,所以应该是这n个人在第一次关灯就打自己脸,不过这么一来就没意思了, ...