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();

Published Monday, April 26, 2004 1:43 AM by Justin Rogers

Comments

No Comments

Leave a Comment

(required) 
(required) 
(optional)
(required)