本文的主要写了C#实现向导页的设计方法与注意事项
一、准备工作
第一步,建立一个Windows窗体应用程序,取名GuideTest
第二步,将主窗体取名FormMain,将StartPosition属性设定为CenterScreen
第三步,建立三个向导页窗体,分别取名FormGuidePage1、FormGuidePage2、FormGuidePage3,将它们的StartPosition属性都设定为CenterScreen。窗体上面放置四个按钮,分别为上一步(btnPrevious)、下一步(btnNext)、提交(btnSubmit)、取消(btnCancel)。
二、建立向导页细节
设立枚举ButtonType,代码如下:
/// <summary>
/// 按钮类型
/// </summary>
[Flags]
public enum ButtonType
{
/// <summary>
/// 默认
/// </summary>
DEFAULT = 0,
/// <summary>
/// 上一步
/// </summary>
PREVIOUS = 1,
/// <summary>
/// 下一步
/// </summary>
NEXT = 2,
/// <summary>
/// 提交
/// </summary>
SUBMIT = 4,
/// <summary>
/// 取消
/// </summary>
CANCEL = 8
}
这段代码中的Flag特性,指示可以将枚举作为位域(即一组标志)处理。将这个枚举类型作为参数传入到向导页中,即可控制某一向导页中四个按钮的可见性。
在每个向导页的构造函数中,都要接受ButtonType类型的枚举作为参数,并用这个参数对按钮可见性进行控制。以FormGuidePage1为例:
/// <summary>
/// 向导页
/// </summary>
/// <param name="buttonType">显示按钮类型</param>
public FormGuidePage1(ButtonType buttonType)
{
InitializeComponent();
//控制按钮可见性
this.btnPrevious.Visible =
(buttonType & ButtonType.PREVIOUS) == ButtonType.PREVIOUS;
this.btnNext.Visible =
(buttonType & ButtonType.NEXT) == ButtonType.NEXT;
this.btnSubmit.Visible =
(buttonType & ButtonType.SUBMIT) == ButtonType.SUBMIT;
this.btnCancel.Visible =
(buttonType & ButtonType.CANCEL) == ButtonType.CANCEL;
}
而在建立FormGuidePage1类型对象时,就需要将需要显示的按钮,中间用逻辑或运算符隔开,传入到对象中,初始化按钮的可见性。如下面这段代码,意为FormGuidePage1中仅下一步和取消按钮是可见的,上一步和提交按钮是不可见的:
FormGuidePage1 formGuidePage1 = new FormGuidePage1(ButtonType.NEXT | ButtonType.CANCEL);
效果示意:
最后,将向导页上的四个按钮分别返回不同的DialogResult,在我的设计中,上一步返回DialogResult.Yes,下一步返回DialogResult.No,提交返回DialogResult.OK,取消返回DialogResult.Cancel
三、连接向导
为FormMain中的按钮btnStart添加Click事件:btnStart_Click,我们可以在这个按钮中实现向导的调用逻辑。下面我用两种方法分别实现了一个场景,即一个包括三个向导页的向导,在第三个向导页上点击“提交”按钮完成向导。
1)连接向导方法1
使用goto语句可以很容易地梳理出来一个流程。需要注意的是FormGuidePage1、2、3三个对象的实例要在最开始new出来,并指定每个向导页里按钮的可见性,如第一页没有上一页按钮,最后一页没有下一页按钮,最后一页要有提交按钮等。
标签按向导页顺序分别为STEP1、STEP2、STEP3,点击上一页按钮,跳转到上一个STEP,点击下一页按钮,跳转到下一个STEP,点击提交按钮,直接跳转到最后一个标签END上,点击取消则直接使用return关键字结束函数的调用。在END标签后,实现对数据的处理操作。
/// <summary>
/// 向导1
/// </summary>
private void Guide1()
{
FormGuidePage1 formGuidePage1 = new FormGuidePage1(ButtonType.NEXT | ButtonType.CANCEL);
FormGuidePage2 formGuidePage2 = new FormGuidePage2(ButtonType.PREVIOUS | ButtonType.NEXT | ButtonType.CANCEL);
FormGuidePage3 formGuidePage3 = new FormGuidePage3(ButtonType.PREVIOUS | ButtonType.CANCEL | ButtonType.SUBMIT);
DialogResult dialogResult;
STEP1: //向导页1
{
dialogResult = formGuidePage1.ShowDialog();
switch (dialogResult)
{
case DialogResult.Yes: //下一步
{
goto STEP2;
}
case DialogResult.Cancel: //取消
{
return;
}
default:
{
return;
}
}
}
STEP2: //向导页2
{
dialogResult = formGuidePage2.ShowDialog();
switch (dialogResult)
{
case DialogResult.Yes: //下一步
{
goto STEP3;
}
case DialogResult.No: //上一步
{
goto STEP1;
}
case DialogResult.Cancel: //取消
{
return;
}
default:
{
return;
}
}
}
STEP3: //向导页3
{
dialogResult = formGuidePage3.ShowDialog();
switch (dialogResult)
{
case DialogResult.No: //上一步
{
goto STEP2;
}
case DialogResult.OK: //提交
{
goto END;
}
case DialogResult.Cancel: //取消
{
return;
}
default:
{
return;
}
}
}
END:
{
//在这里对各页面内保存数据的处理
MessageBox.Show("提交成功");
}
}
2)连接向导方法2
另一种连接向导的方式,可以用有限状态机解决。
先创立一个标记向导中各流程节点状态的枚举:
/// <summary>
/// 向导状态
/// </summary>
public enum GuideStatus
{
/// <summary>
/// 初始状态
/// </summary>
START = 0,
/// <summary>
/// 向导1
/// </summary>
GUIDE1,
/// <summary>
/// 向导2
/// </summary>
GUIDE2,
/// <summary>
/// 向导3
/// </summary>
GUIDE3,
/// <summary>
/// 向导结束
/// </summary>
END,
/// <summary>
/// 流程结束
/// </summary>
FINISH
}
下面的代码通过不断变换流程节点状态,来控制不同向导页之间的跳转关系。
/// <summary>
/// 向导2
/// </summary>
private void Guide2()
{
FormGuidePage1 formGuidePage1 = new FormGuidePage1(ButtonType.NEXT | ButtonType.CANCEL);
FormGuidePage2 formGuidePage2 = new FormGuidePage2(ButtonType.PREVIOUS | ButtonType.NEXT | ButtonType.CANCEL);
FormGuidePage3 formGuidePage3 = new FormGuidePage3(ButtonType.PREVIOUS | ButtonType.CANCEL | ButtonType.SUBMIT);
DialogResult dialogResult;
GuideStatus guideStatus = GuideStatus.START;
while (guideStatus != GuideStatus.FINISH)
{
switch (guideStatus)
{
case GuideStatus.START: //初始状态
{
guideStatus = GuideStatus.GUIDE1;
}
break;
case GuideStatus.GUIDE1: //向导1
{
dialogResult = formGuidePage1.ShowDialog();
switch (dialogResult)
{
case DialogResult.Yes: //下一步
guideStatus = GuideStatus.GUIDE2;
break;
case DialogResult.Cancel: //取消
return;
default:
return;
}
}
break;
case GuideStatus.GUIDE2: //向导2
{
dialogResult = formGuidePage2.ShowDialog();
switch (dialogResult)
{
case DialogResult.Yes: //下一步
guideStatus = GuideStatus.GUIDE3;
break;
case DialogResult.No: //上一步
guideStatus = GuideStatus.GUIDE1;
break;
case DialogResult.Cancel: //取消
return;
default:
return;
}
}
break;
case GuideStatus.GUIDE3: //向导3
{
dialogResult = formGuidePage3.ShowDialog();
switch (dialogResult)
{
case DialogResult.No: //上一步
guideStatus = GuideStatus.GUIDE2;
break;
case DialogResult.OK: //提交
guideStatus = GuideStatus.END;
break;
case DialogResult.Cancel: //取消
return;
default:
return;
}
}
break;
case GuideStatus.END:
{
//在这里对各页面内保存数据的处理
MessageBox.Show("提交成功");
guideStatus = GuideStatus.FINISH;
}
break;
}
}
}
这段代码的功能和方法1中的代码是一样的。
END