Introduction
The AlfaWizard
library is a simple library for the purpose of making wizards. This library allows making a full wizard with just a few lines of source code and with a special *.xml configuration file. This XML file helps in reducing source code lines, because it sets properties for individual pages. Attributes of pages can also be set from the program. The base element of the whole wizard is the main window in which individual pages can be changed according to user actions. The user doesn't have direct access to the main wizard window, but can change the properties through the main wizard class, WizardDialog
.
Background
The wizard behavior can be compared to a finite state machine (FSM). Every page represents a state in an automata. Between individual states, we move with the help of inputs (user inputs). Each page (state of FSM) has some input value, which can be seen from outside. Since an FSM and a simple wizard are so similar, I decided to implement my library with a behavior closest to an FSM. So, it’s possible to choose a wizard page depending on user input.
Using the Code
In the making of the AlfaWizard
library, my intention was to reduce the number of lines in the source code which the user must write. This was fulfilled with the use of the XML configuration file. The various XML elements are used by BasePage
, from which all the pages used in a wizard must be derived. In the attached test project, in the class TestClass
, you can see how the user just needs a very small number of lines to make a good wizard. The library also contains a set of exceptions which can help in the debugging phase of an application.
Name | Description |
BaseException | All other AlfaWizard exceptions are derived from this basic exception BaseException . This exception has no additional data. |
InitException | Thrown during the initialization process of a page. |
PageInsertException | This exception is thrown when you try to insert a non-initialized page into WizardDialog . |
ParseException | This exception is thrown when some exception is thrown when reading the XML configuration file. |
PageNotFoundException | This exception is thrown when you try to use a page that is not in the WizardDialog . |
In the test project, you can also find how to derive your own page and use it in the wizard. The pages already available for the wizard are thread safe. In the case of transferring data between pages, I use some interfaces like IDirBrowse
or ILicenseAccept
. For example, to get in the ProgressPage
path where the zip file should by unzipped, we do:
progress.AutoJumpNext = true;
progress.BrowsePageId = browse.Information.Id;
progress.ProgDeleg = WorkingTest;
Example 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);
wd = new WizardDialog(Path.Combine(dirPath, "configFile.xml"), "en");
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);
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);
test.Initialize(testBack, testNext);
alfa.Initialize(test, final);
beta.Initialize(test, final);
final.Initialize(test, null);
wd.PageAdd(intro);
wd.PageAdd(final);
wd.PageAdd(license);
wd.PageAdd(test);
wd.PageAdd(alfa);
wd.PageAdd(beta);
}
public void Run()
{
wd.ShowWizard();
}
}
How To Create Your Own Page
In case you want to create your own page for a wizard without added functionalities, you just need to create a new control and add this code to it:
public partial class AlfaPage : BasePage
{
public AlfaPage()
{
InitializeComponent();
}
public AlfaPage(WizardDialog wd) : base (wd)
{
InitializeComponent();
}
public AlfaPage(WizardDialog wd, string name) : base(wd, name)
{
InitializeComponent();
}
public AlfaPage(WizardDialog wd, string name, WindowButtons dialogButtons)
: base(wd, name, dialogButtons)
{
InitializeComponent();
}
}
Here is a description of all the important methods that are available in the BasePage
class. In case you want to override some methods, you must always call the base method first. The base method invokes events that could be processed and to which the wizard reacts.
Method name (all methods are public, parameters are skipped) | Description |
bool Initialize | This method is called by the page initialization where the predecessors and followers are stated. In this method, page settings are read from the configuration file. |
PageInformation RunBack | This method is called when the user clicks on the “Back” button. |
PageInformation RunNext | This method is called when the user clicks on the “Next” button. |
bool WorkBeforeShow | This method is called before the page is shown in the wizard window. |
bool WorkAfterShow | This method is called after the page is shown in the wizard window. |
bool WorkBeforeBack | This method is called before replacing the actual page with the previous page. |
bool WorkBeforeNext | This method is called before replacing the actual page with the next page. |
bool WorkCancel | This method is called when the user closes the wizard window. This method is called to cascade all the previous pages of the wizard. |
string ToString | Do not override this method if you want to use the WizardLogger class. |
An Example of the XML Configuration File
The included example contains a configuration file, which is used for setting the attributes of individual wizard pages. The file is named configFile.xml and its base structure looks like this:
="1.0"="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>
<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>
Future Development
Considering that the user has no access to the main application window, I plan in future to bring all element properties of the main window to the class WizardDialog
and also to the configuration file.
History
- 21.08.2008 - First version of article
- 30.08.2008 - New library version (0.0.1.0) see in changelog
Change Log
- Version 0.0.0.1 released 21.08.2008
- First official version of library
- Version 0.0.1.0 released 30.08.2008
- Changed return values to
void
of methods WizardDialog.RunBack()
and WizardDialog.RunNext()
New readonly attribute PreviousPage
, which helps you to get back page especially (back from state 6 to state 4 or 5)- New
WizardDialog
constructor, WizardDialog(Stream xmlStream, string language)
- Removed method
ReadFromFile(string path, string xpath)
New method ReadFromXml(Stream xmlStream, string xpath)
which replaces old method ReadFromFile
Special Thanks
I want to say thanks to all the people that have helped me with this article. In the first place, thanks to Ing. Ondrej Plocica for the theoretical help and advice. Secondly, thanks to Ing. Peter Gregan for helping me with the translation.