65.9K
CodeProject 正在变化。 阅读更多。
Home

AlfaWizard 库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.61/5 (14投票s)

2008年8月21日

CPOL

5分钟阅读

viewsIcon

31371

downloadIcon

347

AlfaWizard 是一个简单的库,用于创建向导。

introPage.jpg

引言

AlfaWizard 库是一个简单的库,用于创建向导。该库允许通过几行源代码和一个特殊的*.xml配置文件来创建完整的向导。此 XML 文件有助于减少源代码行数,因为它设置了各个页面的属性。页面的属性也可以从程序中设置。整个向导的基础元素是主窗口,其中各个页面可以根据用户操作进行更改。用户无法直接访问主向导窗口,但可以通过主向导类WizardDialog更改属性。

背景

向导的行为可以与有限状态机(FSM)进行比较。每个页面都代表自动机中的一个状态。我们在输入(用户输入)的帮助下在各个状态之间移动。每个页面(FSM 的状态)都有一个可以从外部看到的输入值。由于 FSM 和简单的向导非常相似,我决定用最接近 FSM 的行为来实现我的库。因此,可以根据用户输入选择向导页面。

AlfaWizard1.jpg

Using the Code

在创建AlfaWizard 库时,我的目的是减少用户必须编写的源代码行数。通过使用 XML 配置文件实现了这一点。BasePage使用各种 XML 元素,向导中使用的所有页面都必须从此派生。在附带的测试项目中,在TestClass类中,您可以看到用户只需很少的行数即可创建一个好的向导。该库还包含一组异常,可以帮助调试应用程序。

名称 描述
BaseException 所有其他AlfaWizard 异常都从此基本异常BaseException派生。此异常没有附加数据。
InitException 在页面初始化过程中引发。
PageInsertException 当您尝试将未初始化的页面插入WizardDialog时,将引发此异常。
ParseException 读取 XML 配置文件时引发任何异常时,将引发此异常。
PageNotFoundException 当您尝试使用WizardDialog中不存在的页面时,将引发此异常。

在测试项目中,您还可以找到如何派生自己的页面并在向导中使用它。向导已提供的页面是线程安全的。在页面之间传输数据的情况下,我使用了一些接口,如IDirBrowseILicenseAccept。例如,要在ProgressPage中获取解压缩 zip 文件的路径,我们这样做:

//automatically jumps to next page if it’s a 100% on progress bar
progress.AutoJumpNext = true;
//id of the page that must implement IDirBrowse, 
//from which you get a path where zip archive is unzipped
progress.BrowsePageId = browse.Information.Id;
//operation that starts in separate thread after the page is shown
progress.ProgDeleg = WorkingTest;

示例 TestClass

public class TestClass
{
    private readonly string dirPath;
    private WizardDialog wd;
    private IntroPage intro;
    private LicensePage license;
    private FinalPage final;

    private TestPage test;
    private AlfaPage alfa;
    private BetaPage beta;

    public TestClass ()
    {
        dirPath = Path.GetDirectoryName(
          Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);
        //create object WizardDialog, where 2nd argument in constructor is language
        wd = new WizardDialog(Path.Combine(dirPath, "configFile.xml"), "en");

        //create object intro page, 1st argument is object type of WizardDialog, 
        //2nd is page name in XML file, 3rd is allowed wizard buttons
        intro = new IntroPage(wd, "My Intro Page", WindowButtons.NextCancel);

        license = new LicensePage(wd, "My license page", WindowButtons.BackNextCancel);
        test = new TestPage(wd, "My own test page", WindowButtons.BackNextCancel);
        final = new FinalPage(wd, "Designer final page", WindowButtons.BackNextCancel);
        alfa = new AlfaPage(wd, "AlfaPage", WindowButtons.BackNextCancel);
        beta = new BetaPage(wd, "BetaPage", WindowButtons.BackNextCancel);

        //now we specify previous and next page for intro page
        intro.Initialize(null, license); 

        license.Initialize(intro, test);
        PageInformationCollection testBack = new PageInformationCollection();
        testBack.Add(license.Information);
        PageInformationCollection testNext = new PageInformationCollection();
        testNext.Add(alfa.Information);
        testNext.Add(beta.Information);
        //now we specify one previous page and two next pages for test page
        test.Initialize(testBack, testNext);

        alfa.Initialize(test, final);
        beta.Initialize(test, final);
        final.Initialize(test, null);

        //after page initialization you must insert page 
        //into WizardDialog.Pages collection
        wd.PageAdd(intro);
        wd.PageAdd(final);
        wd.PageAdd(license);
        wd.PageAdd(test);
        wd.PageAdd(alfa);
        wd.PageAdd(beta);
    }

    public void Run()
    {
        //now we show wizard
        wd.ShowWizard();
    }
}

如何创建自己的页面

如果您想为没有附加功能的向导创建自己的页面,只需创建一个新控件并将此代码添加到其中即可。

public partial class AlfaPage : BasePage
//control inherit from BasePage
{
    //this constructor is mandatory
    public AlfaPage()
    {
        InitializeComponent();
    }

    //this constructor is mandatory
    public AlfaPage(WizardDialog wd) : base (wd)
    {
        InitializeComponent();
    }

    //this constructor is mandatory
    public AlfaPage(WizardDialog wd, string name) : base(wd, name)
    {
        InitializeComponent();
    }

    //this constructor is mandatory
    public AlfaPage(WizardDialog wd, string name, WindowButtons dialogButtons)
         : base(wd, name, dialogButtons)
    {
        InitializeComponent();
    }
}

此处描述了BasePage类中所有重要的方法。如果您想覆盖某些方法,必须始终先调用基类方法。基类方法会调用可以处理并由向导响应的事件。

方法名称(所有方法均为公共,参数已省略) 描述
bool Initialize 这是由页面初始化调用的方法,其中指定了前驱和后继。在此方法中,页面设置从配置文件读取。
PageInformation RunBack 当用户单击“后退”按钮时,调用此方法。
PageInformation RunNext 当用户单击“下一步”按钮时,调用此方法。
bool WorkBeforeShow 在页面显示在向导窗口中之前调用此方法。
bool WorkAfterShow 在页面显示在向导窗口中之后调用此方法。
bool WorkBeforeBack 在用前一页替换当前页之前调用此方法。
bool WorkBeforeNext 在用下一页替换当前页之前调用此方法。
bool WorkCancel 当用户关闭向导窗口时调用此方法。调用此方法以级联向导的所有前一页。
string ToString 如果要使用WizardLogger类,请不要覆盖此方法。

XML 配置文件示例

包含的示例包含一个配置文件,用于设置各个向导页面的属性。文件名为configFile.xml,其基本结构如下:

<?xml version="1.0" encoding="utf-8" ?>
    <Wizard> 
      <WizardDialog>
       <Language type="en">
              <BackButtonName>Back</BackButtonName>
              <NextButtonName>Next</NextButtonName>
              <FinishButtonName>Finish</FinishButtonName>
              <CancelButtonName>Cancel</CancelButtonName>
              <CancelWizardMsg>Do you want cancel this dialog?</CancelWizardMsg>
          <WizardHeaderMsg>Warning</WizardHeaderMsg>
        </Language>
      </WizardDialog>
      <IntroPage name="My Intro Page">
        <Language type="en">
         <Purpose>This is purpose of dialog</Purpose>
          <WindowTitle>Window title 1</WindowTitle>
          <ActionName>Action name 1</ActionName>
          <ActionDescription>Action description 1</ActionDescription>
          <HeaderImagePath></HeaderImagePath>
        </Language>
      </IntroPage>
      <LicensePage name="My license page">
        <Language type="en">
          <WindowTitle>Window title 2</WindowTitle>
          <ActionName>Action name 2</ActionName>
          <ActionDescription>Action description 2</ActionDescription>
          <HeaderImagePath></HeaderImagePath>
          <LicenseText>test</LicenseText>
          <!--<LicenseText type="rtf">paste rtf document here</LicenseText>-->
          <Accept>I agree license agreement</Accept>
          <Refuse>I not accept license agreement</Refuse>
          <NotValidText>You must accept license agreement 
                        before continue!</NotValidText>
        </Language>
      </LicensePage>
      <FinalPage name="Designer final page">
        <Language type="en">
          <WindowTitle>Window title 4</WindowTitle>
          <ActionName>Action name 4</ActionName>
          <ActionDescription>Action description 4</ActionDescription>
          <HeaderImagePath></HeaderImagePath>
        </Language>
      </FinalPage>
      <TestPage name="My own test page">
        <Language type="en">
          <WindowTitle>Window title 3</WindowTitle>
          <ActionName>Action name 3</ActionName>
          <ActionDescription>Action description 3</ActionDescription>
          <HeaderImagePath></HeaderImagePath>
        </Language>
      </TestPage>
    </Wizard>

未来发展

考虑到用户无法访问主应用程序窗口,我计划将来将主窗口的所有元素属性都引入WizardDialog类以及配置文件中。

历史

  • 2008年8月21日 - 文章初版
  • 2008年8月30日 - 新库版本 (0.0.1.0),请参阅变更日志

更改日志

  • 版本 0.0.0.1 发布于 2008 年 8 月 21 日
    • 库的第一个正式版本
  • 版本 0.0.1.0 发布于 2008 年 8 月 30 日
    • 将方法WizardDialog.RunBack() WizardDialog.RunNext()的返回类型更改为void
    • 新的只读属性PreviousPage,有助于获取返回页面,尤其是在(从状态 6 返回到状态 4 或 5)时
    • 新的WizardDialog 构造函数,WizardDialog(Stream xmlStream, string language)
    • 移除方法ReadFromFile(string path, string xpath)
    • 新的方法ReadFromXml(Stream xmlStream, string xpath),取代旧方法ReadFromFile

特别感谢

我想感谢所有帮助我完成这篇文章的人。首先,感谢 Ing. Ondrej Plocica 提供理论帮助和建议。其次,感谢 Ing. Peter Gregan 帮助我进行翻译。

© . All rights reserved.