在软件开发中,对于需要比较复杂,需要多步完成的操作,我们一般采用向导的方式来提供用户界面。向导设计本身并不困难,但如果要做到通用性强,模块间尽量低耦合,我们还是得动一下脑筋的。下面介绍一下我的实现方式。
典型的向导界面,主界面上一般包含两个区域,一是选项区域,二是按钮区域,包含上一步,下一步,取消等按钮。向导执行后,每一步该做什么,如果通过条件判断来进行,显然会非常麻烦。理想的做法是,上一步的代码为:
GoLast();
下一步的代码为:
GoNext();
那怎么做到这一点呢?
首先概念上,我们明确,向导由若干步组成,每一步可以由一个UserControl来表示,执行到该步时,只是创建一个该控件的实例,并显示在向导主界面的选项区域而已,这一点是不难做到的。那么现在问题的关键就是将这些步串联起来,能够做到自动的运行。这个任务可以分散到每一步的控件中去,也就是说,每一步应当知道它的上一步是什么,下一步它该做什么,这一点在逻辑上应当是没有疑虑的。所以,我设计了一个接口IWizardStep,代码如下:
{
Control NextStepControl
{
get;
}
Control LastStepControl
{
get;set;
}
void BeforeGoNext();
}
其中, NextStepControl表示下一步的控件,如果是最后一步,则应为null,;LastStepControl表示上一步控件,如果是第一步,则该值应null 。BeforeGoNext用于在执行下一步时,做一些选项的应用等预处理工作。每一步的控件只要实现了该接口,向导中的各个步骤就有次序的连接在一起了。
有了上面的这些工作,我们只需要再设计一个用来供主界面调用的外观类,向导就可以很好的运行了。
public class WizardFacade
{
private System.Windows.Forms.Control m_ParentControl;
private System.Windows.Forms.Control m_CurrentControl;
public WizardFacade(Control parentControl)
{
m_ParentControl =parentControl;
EntranceControl ctl = new EntranceControl()
SetCurrentControl(selctl);
}
/// <summary>
/// 将某一个控件设为当前控件,并显示出来
/// </summary>
/// <param name="subControl"></param>
private void SetCurrentControl(Control subControl)
{
if (m_CurrentControl != null)
{
(subControl as IWizardStep).Chart = (m_CurrentControl as IWizardStep).Chart;
(subControl as IWizardStep).LastStepControl = m_CurrentControl;
}
subControl.Parent = m_ParentControl;
subControl.Location = new System.Drawing.Point(0,0);
subControl.BringToFront();
subControl.Visible = true;
m_CurrentControl = subControl;
}
/// <summary>
/// 执行下一步
/// </summary>
public void GoNext()
{
(m_CurrentControl as IWizardStep).BeforeGoNext();
if ((m_CurrentControl as IWizardStep).NextStepControl != null)
{
SetCurrentControl((m_CurrentControl as IWizardStep).NextStepControl);
}
}
/// <summary>
/// 执行上一步
/// </summary>
public void GoLast()
{
if ((m_CurrentControl as IWizardStep).LastStepControl != null)
SetCurrentControl((m_CurrentControl as IWizardStep).LastStepControl);
}
/// <summary>
/// 获取当前正在显示的控件
/// </summary>
/// <returns></returns>
public Control CurrentStepControl
{
get
{
return m_CurrentControl;
}
}
}
需要注意的是,在构造函数中,有一个EntranceControl的变量,是入口控件,也就是向导的第一步要显示的控件。在外观类中明确该控件,在职现分配上应当也是符合逻辑的。
做完了这些,我们的向导主界面就非常简单了,只需要创建一个WizardFacade对象实例,然后调用相应的方法就可以了。
实践证明,上述思路简单,清晰,实用,稍作扩展,可以实现更强大的功能,或者定制你业务中所需要的功能。