Code-Only: Winforms Wizard Series Article 5 (JScript .NET)
import System;
import System.Collections;
import System.ComponentModel;
import System.Threading;
import System.Windows.Forms;
public interface IWizardDialog {
function get NavigatePrevious() : Control
function get NavigateNext() : Control
function get NavigateFinish() : Control
function get UIRoot() : Control
function get Display() : boolean
function set Display(value:boolean)
}
public interface IWizardPanel {
function get ShowNavigatePrevious() : boolean
function get ShowNavigateNext() : boolean
function get ShowNavigateFinish() : boolean
}
public interface IWizardNavigation {
function get SupportNamedNavigation() : boolean
function get NavigateName() : String
function get NavigatePreviousTarget() : String
function get NavigateNextTarget() : String
}
public class WizardController extends ApplicationContext {
private var complete:boolean = false;
private var wizardIndex:int = -1;
private var wizardDialog:IWizardDialog = null;
private var wizardPanels:ArrayList = new ArrayList();
private var nameMap:Hashtable = new Hashtable();
public function WizardController() { }
public function SetDialog(dialog:Form) : void {
if ( !(dialog instanceof IWizardDialog) ) {
throw new Exception("Wizard dialogs must support IWizardDialog");
}
wizardDialog = IWizardDialog(Object(dialog));
if ( wizardDialog.NavigatePrevious == null ) {
throw new Exception("Wizard dialogs must have a Previous Button");
}
if ( wizardDialog.NavigateNext == null ) {
throw new Exception("Wizard dialogs must have a Next Button");
}
if ( wizardDialog.NavigateFinish == null ) {
throw new Exception("Wizard dialogs must have a Finish Button");
}
if ( wizardDialog.UIRoot == null ) {
throw new Exception("Wizard dialogs must have a non null UI Root");
}
wizardDialog.NavigatePrevious.add_Click(this.Wizard_NavigatePrevious)
wizardDialog.NavigateNext.add_Click(this.Wizard_NavigateNext);
wizardDialog.NavigateFinish.add_Click(this.Wizard_NavigateFinish);
// Last time we get a chance on the Form object
dialog.add_Closing(Wizard_Closing);
}
public function AddPanel(pnl:Control) : void {
if ( !(pnl instanceof IWizardPanel) ) {
throw new Exception("Wizard panels must support IWizardPanel");
}
if ( pnl instanceof IWizardNavigation ) {
var iwn:IWizardNavigation = IWizardNavigation(Object(pnl));
if ( nameMap.ContainsKey(iwn.NavigateName) ) {
throw new Exception("Wizard Navigation Panels can't share names");
}
nameMap[iwn.NavigateName] = iwn;
}
wizardPanels.Add(pnl);
}
public function get Complete() : boolean { return complete; }
public function get Panels() : ArrayList { return wizardPanels; }
public function Wizard_Closing(sender:Object, e:CancelEventArgs) : void {
MessageBox.Show("You must complete the wizard in order to exit.");
e.Cancel = true;
}
public function Wizard_NavigateFinish(sender:Object, e:EventArgs) : void {
// this could be fired anywhere in case you have an opt out
// early button on any of your forms.
wizardDialog.UIRoot.Controls.Clear();
wizardDialog.Display = false;
complete = true;
ExitThread();
}
public function Wizard_NavigateNext(sender:Object, e:EventArgs) : void {
var wizardNav:IWizardNavigation =
(wizardPanels[wizardIndex] instanceof IWizardNavigation) ?
IWizardNavigation(wizardPanels[wizardIndex]) :
null;
if ( wizardNav != null && wizardNav.SupportNamedNavigation ) {
if ( nameMap.ContainsKey(wizardNav.NavigateNextTarget) ) {
wizardIndex = wizardPanels.IndexOf(nameMap[wizardNav.NavigateNextTarget]);
} else {
// Since we can't find the next panel, we pop out
// and finish. Same as if we walked off the end
// of the array before.
wizardIndex = wizardPanels.Count;
}
} else {
wizardIndex++;
}
if ( wizardIndex == wizardPanels.Count ) {
Wizard_NavigateFinish(sender, e); // This shouldn't happen if your dialogs are correct
return;
}
if ( wizardPanels[wizardIndex] instanceof Control ) {
InitPanel(Control(wizardPanels[wizardIndex]));
}
}
public function Wizard_NavigatePrevious(sender:Object, e:EventArgs) : void {
var wizardNav:IWizardNavigation =
(wizardPanels[wizardIndex] instanceof IWizardNavigation) ?
IWizardNavigation(wizardPanels[wizardIndex]) :
null;
if ( wizardNav != null && wizardNav.SupportNamedNavigation ) {
if ( nameMap.ContainsKey(wizardNav.NavigatePreviousTarget) ) {
wizardIndex = wizardPanels.IndexOf(nameMap[wizardNav.NavigatePreviousTarget]);
} else {
// Can't go back from here I guess
// This actually isn't bad, but the user should
// have specified that no previous button be available.
return;
}
} else {
if ( wizardIndex > 0 ) {
wizardIndex--;
} else {
return;
}
}
if ( wizardPanels[wizardIndex] instanceof Control ) {
InitPanel(Control(wizardPanels[wizardIndex]));
}
}
public function StartWizard() : void {
if ( wizardPanels.Count == 0 ) {
throw new Exception("Must add panels to the wizard");
}
if ( wizardIndex != -1 && !complete ) {
throw new Exception("Wizard has already been started");
}
complete = false;
wizardIndex = 0;
if ( wizardPanels[wizardIndex] instanceof Control ) {
InitPanel(Control(wizardPanels[wizardIndex]));
}
wizardDialog.Display = true;
}
private function InitPanel(wizardPanel:Control) : void {
wizardPanel.Dock = DockStyle.Fill;
if ( wizardPanel instanceof IWizardPanel ) {
wizardDialog.NavigatePrevious.Enabled = IWizardPanel(Object(wizardPanel)).ShowNavigatePrevious;
wizardDialog.NavigateNext.Enabled = IWizardPanel(Object(wizardPanel)).ShowNavigateNext;
wizardDialog.NavigateFinish.Enabled = IWizardPanel(Object(wizardPanel)).ShowNavigateFinish;
}
wizardDialog.UIRoot.Controls.Clear();
wizardDialog.UIRoot.Controls.Add(wizardPanel);
}
}
public class WizardPanel extends DesignablePanel {
protected var description:String = null;
protected var lblDescription:Label = new Label();
public function WizardPanel(description:String, prev:boolean, next:boolean, finish:boolean) {
this.prev = prev;
this.next = next;
this.finish = finish;
this.description = description;
InitializeComponent();
}
private function InitializeComponent() : void {
this.lblDescription.Dock = DockStyle.Fill;
this.lblDescription.Text = this.description;
this.Controls.Add(this.lblDescription);
}
}
public class WizardPanelWithNavigation extends DesignablePanelWithNavigation {
protected var description:String = null;
protected var lblDescription:Label = new Label();
public function WizardPanelWithNavigation(name:String, description:String, prev:String, next:String, finish:boolean) {
this.name = name;
this.nextPanel = next;
this.prevPanel = prev;
this.finish = finish;
this.description = description;
InitializeComponent();
}
private function InitializeComponent() : void {
this.lblDescription.Dock = DockStyle.Fill;
this.lblDescription.Text = this.description;
this.Controls.Add(this.lblDescription);
}
}
public class DesignablePanel extends UserControl implements IWizardPanel {
protected var prev:boolean = false;
protected var next:boolean = false;
protected var finish:boolean = false;
public function DesignablePanel() { }
BrowsableAttribute(false) public function get ShowNavigatePrevious() : boolean { return this.prev; }
BrowsableAttribute(false) public function get ShowNavigateNext() : boolean { return this.next; }
BrowsableAttribute(false) public function get ShowNavigateFinish() : boolean { return this.finish; }
BrowsableAttribute(true)
CategoryAttribute("Wizard")
DescriptionAttribute("Determines if the Previous button is activated when this panel is displayed")
public function get NavigatePrevious() : boolean { return this.prev; }
public function set NavigatePrevious(value:boolean) { this.prev = value; }
BrowsableAttribute(true)
CategoryAttribute("Wizard")
DescriptionAttribute("Determines if the Next button is activated when this panel is displayed")
public function get NavigateNext() : boolean { return this.next; }
public function set NavigateNext(value:boolean) { this.next = value; }
BrowsableAttribute(true)
CategoryAttribute("Wizard")
DescriptionAttribute("Determines if the Finish button is activated when this panel is displayed")
public function get NavigateFinish() : boolean { return this.finish; }
public function set NaviagteFinish(value:boolean) { this.next = value; }
}
public class DesignablePanelWithNavigation extends DesignablePanel implements IWizardNavigation {
protected var name:String = null;
protected var nextPanel:String = null;
protected var prevPanel:String = null;
public function DesignablePanelWithNavigation() { }
BrowsableAttribute(false) public function get SupportNamedNavigation() : boolean { return (this.nextPanel != null || this.prevPanel != null); }
BrowsableAttribute(false) public function get NavigateName() : String { return this.name; }
BrowsableAttribute(false) public function get NavigatePreviousTarget() : String { return this.prevPanel; }
BrowsableAttribute(false) public function get NavigateNextTarget() : String { return this.nextPanel; }
BrowsableAttribute(false) public override function get ShowNavigatePrevious() : boolean { return this.prevPanel != null; }
BrowsableAttribute(false) public override function get ShowNavigateNext() : boolean { return this.nextPanel != null; }
BrowsableAttribute(false)
public override function get NavigatePrevious() : boolean { return ShowNavigatePrevious; }
public override function set NavigatePrevious(value:boolean) { }
BrowsableAttribute(false)
public override function get NavigateNext() : boolean { return ShowNavigateNext; }
public override function set NavigateNext(value:boolean) { }
BrowsableAttribute(true)
CategoryAttribute("Wizard")
DescriptionAttribute("Sets the name of this wizard panel for navigation purposes. Each panel" +
"within a WizardController must have a unique name.")
public function get PanelName() : String { return this.name; }
public function set PanelName(value:String) { this.name = value; }
BrowsableAttribute(true)
CategoryAttribute("Wizard")
DescriptionAttribute("Sets the name of the next panel in the series. This property, if set, enables" +
"the SupportNamedNavigation feature and the display of the Next button within" +
"a WizardDialog")
public function get NextTargetName() : String { return this.nextPanel; }
public function set NextTargetName(value:String) { this.nextPanel = value; }
BrowsableAttribute(true)
CategoryAttribute("Wizard")
DescriptionAttribute("Sets the name of the previous panel in the series. This property, if set, enables" +
"the SupportNamedNavigation feature and the display of the Previous button within" +
"a WizardDialog")
public function get PreviousTargetName() : String { return this.prevPanel; }
public function set PreviousTargetName(value:String) { this.prevPanel = value; }
}
public class DesignableWizardDialog extends Form implements IWizardDialog {
protected var previousButton:Control;
protected var nextButton:Control;
protected var finishButton:Control;
protected var uiRoot:Control;
public function DesignableWizardDialog() { }
BrowsableAttribute(false) public function get NavigatePrevious() : Control { return previousButton; }
BrowsableAttribute(false) public function get NavigateNext() : Control { return nextButton; }
BrowsableAttribute(false) public function get NavigateFinish() : Control { return finishButton; }
BrowsableAttribute(false) public function get UIRoot() : Control { return uiRoot; }
BrowsableAttribute(false)
public function get Display() : boolean { return this.Visible; }
public function set Display(value:boolean) { this.Visible = value; }
BrowsableAttribute(true)
CategoryAttribute("Wizard")
DescriptionAttribute("Set the control used for previous panel navigation")
public function get NavigatePreviousControl() : Control { return this.previousButton; }
public function set NavigatePreviousControl(value:Control) { this.previousButton = value; }
BrowsableAttribute(true)
CategoryAttribute("Wizard")
DescriptionAttribute("Set the control used for previous panel navigation")
public function get NavigateNextControl() : Control { return this.nextButton; }
public function set NavigateNextControl(value:Control) { this.nextButton = value; }
BrowsableAttribute(true)
CategoryAttribute("Wizard")
DescriptionAttribute("Set the control used for previous panel navigation")
public function get NavigateFinishControl() : Control { return this.finishButton; }
public function set NavigateFinishControl(value:Control) { this.finishButton = value; }
BrowsableAttribute(true)
CategoryAttribute("Wizard")
DescriptionAttribute("Sets the control where all panels will be displayed")
public function get UIRootControl() : Control { return this.uiRoot; }
public function set UIRootControl(value:Control) { this.uiRoot = value; }
}
public class WizardTestDialog extends DesignableWizardDialog {
private var bottomPanel:Panel = new Panel();
private var title:String;
public function WizardTestDialog(title:String) {
this.title = title;
InitializeComponent();
}
private function InitializeComponent() : void {
// Create our large containers
// Top for wizard
// Bottom for navigation
this.bottomPanel = new Panel();
this.bottomPanel.Height = 30;
this.bottomPanel.Dock = DockStyle.Bottom;
this.uiRoot = new Panel();
this.uiRoot.Dock = DockStyle.Fill;
this.Text = title;
var layer1:Control[] = new Control[2];
layer1[0] = uiRoot;
layer1[1] = bottomPanel;
this.Controls.AddRange(layer1);
this.finishButton = new Button();
this.finishButton.Text = "Finish";
this.finishButton.Left = this.bottomPanel.Width - (this.finishButton.Width + 10);
this.finishButton.Anchor = AnchorStyles.Right;
this.nextButton = new Button();
this.nextButton.Text = "Next";
this.nextButton.Left = this.finishButton.Left - (this.nextButton.Width + 5);
this.nextButton.Anchor = AnchorStyles.Right;
this.previousButton = new Button();
this.previousButton.Text = "Previous";
this.previousButton.Left = this.nextButton.Left - (this.previousButton.Width + 5);
this.previousButton.Anchor = AnchorStyles.Right;
var layer2:Control[] = new Control[3];
layer2[0] = previousButton;
layer2[1] = nextButton;
layer2[2] = finishButton;
this.bottomPanel.Controls.AddRange(layer2);
}
}
public class WizardTester {
STAThreadAttribute()
public static function Main() : void {
var controller:WizardController = new WizardController();
controller.SetDialog(new WizardTestDialog("What do you want?"));
controller.AddPanel(new WizardPanel("foo 1", false, true, false));
controller.AddPanel(new WizardPanel("foo 2", true, true, false));
controller.AddPanel(new WizardPanel("foo 3", true, true, false));
controller.AddPanel(new WizardPanel("foo 4", true, true, true));
controller.AddPanel(new WizardPanel("foo 5", true, false, true));
controller.StartWizard();
Application.Run(controller);
controller = new WizardController();
controller.SetDialog(new WizardTestDialog("What do you want?"));
controller.AddPanel(new WizardPanelWithNavigation("Panel 1", "Welcome Screen!", null, "Panel 3", false));
controller.AddPanel(new WizardPanelWithNavigation("Panel 2", "License Agreement!", "Panel 3", "Panel 4", false));
controller.AddPanel(new WizardPanelWithNavigation("Panel 3", "Install Options", "Panel 1", "Panel 2", false));
controller.AddPanel(new WizardPanelWithNavigation("Panel 4", "Confirmation Screen", "Panel 2", "Panel 5", false));
controller.AddPanel(new WizardPanelWithNavigation("Panel 5", "Install Now!", null, null, true));
controller.StartWizard();
Application.Run(controller);
}
}
WizardTester.Main();