Code-Only: Winforms Wizard Series Article 3 (C#)

using System;
using System.Collections;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

public interface IWizardDialog {
    Control NavigatePrevious { get; }
    Control NavigateNext { get; }
    Control NavigateFinish { get; }
    Control UIRoot { get; }
    bool Display { get; set; }
}

public interface IWizardPanel {
    bool ShowNavigatePrevious { get; }
    bool ShowNavigateNext { get; }
    bool ShowNavigateFinish { get; }
}

public interface IWizardNavigation {
    bool SupportNamedNavigation { get; }
    string NavigateName { get; }
    string NavigatePreviousTarget { get; }
    string NavigateNextTarget { get; }
}

public class WizardController : ApplicationContext {
    private bool complete = false;
    private int wizardIndex = -1;
    private IWizardDialog wizardDialog = null;
    private ArrayList wizardPanels = new ArrayList();
    private Hashtable nameMap = new Hashtable();

    public WizardController() { }
   
    public void SetDialog(Form dialog) {
        IWizardDialog wDialog = dialog as IWizardDialog;
   
        if ( wDialog != null ) {
            if ( wDialog.NavigatePrevious == null ) {
                throw new Exception("Wizard dialogs must have a Previous Button");
            }
            if ( wDialog.NavigateNext == null ) {
                throw new Exception("Wizard dialogs must have a Next Button");
            }
            if ( wDialog.NavigateFinish == null ) {
                throw new Exception("Wizard dialogs must have a Finish Button");
            }
            if ( wDialog.UIRoot == null ) {
                throw new Exception("Wizard dialogs must have a non null UI Root");
            }
        } else {
            throw new Exception("Wizard dialogs must support IWizardDialog");
        }

        wizardDialog = wDialog;
        wizardDialog.NavigatePrevious.Click += new EventHandler(Wizard_NavigatePrevious);
        wizardDialog.NavigateNext.Click += new EventHandler(Wizard_NavigateNext);
        wizardDialog.NavigateFinish.Click += new EventHandler(Wizard_NavigateFinish);
       
        // Last time we get a chance on the Form object
        dialog.Closing += new CancelEventHandler(Wizard_Closing);
    }
   
    public void AddPanel(Panel pnl) {
        IWizardPanel wPanel = pnl as IWizardPanel;
        IWizardNavigation wNav = pnl as IWizardNavigation;

        if ( wPanel == null ) {
            throw new Exception("Wizard panels must support IWizardPanel");
        }

        if ( wNav != null ) {
            if ( nameMap.ContainsKey(wNav.NavigateName) ) {
                throw new Exception("Wizard Navigation Panels can't share names");
            }

            nameMap[wNav.NavigateName] = wNav;
        }

        wizardPanels.Add(wPanel);
    }
   
    public bool Complete {
        get {
            return complete;
        }
    }
   
    public ArrayList Panels {
        get {
            return wizardPanels;
        }
    }
   
    public void Wizard_Closing(object sender, CancelEventArgs e) {
        MessageBox.Show("You must complete the wizard in order to exit.");
        e.Cancel = true;
    }
   
    public void Wizard_NavigateFinish(object sender, EventArgs e) {
        // 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 void Wizard_NavigateNext(object sender, EventArgs e) {
        IWizardNavigation wizardNav = wizardPanels[wizardIndex] as IWizardNavigation;

        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;
        }

        Panel newPanel = wizardPanels[wizardIndex] as Panel;

        if ( newPanel != null ) {
            InitPanel(newPanel);
        }
    }

    public void Wizard_NavigatePrevious(object sender, EventArgs e) {
        IWizardNavigation wizardNav = wizardPanels[wizardIndex] as IWizardNavigation;
        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;
            }
        }

        Panel newPanel = wizardPanels[wizardIndex] as Panel;

        if ( newPanel != null ) {
            InitPanel(newPanel);
        }
    }
   
    public void StartWizard() {
        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;
        Panel startPanel = wizardPanels[wizardIndex] as Panel;
        if ( startPanel != null ) {
            InitPanel(startPanel);
        }
        wizardDialog.Display = true;
    }

    private void InitPanel(Panel wizardPanel) {
        wizardPanel.Dock = DockStyle.Fill;
       
        wizardDialog.NavigatePrevious.Enabled   = ((IWizardPanel) wizardPanel).ShowNavigatePrevious;
        wizardDialog.NavigateNext.Enabled       = ((IWizardPanel) wizardPanel).ShowNavigateNext;
        wizardDialog.NavigateFinish.Enabled     = ((IWizardPanel) wizardPanel).ShowNavigateFinish;
       
        wizardDialog.UIRoot.Controls.Clear();
        wizardDialog.UIRoot.Controls.Add(wizardPanel);
    }
}

public class WizardPanel : Panel, IWizardPanel {
    private bool prev;
    private bool next;
    private bool finish;
   
    private Label description = new Label();
   
    public WizardPanel(string description, bool prev, bool next, bool finish) {
        this.prev = prev;
        this.next = next;
        this.finish = finish;
        this.description.Text = description;
       
        InitializeComponent();
    }
   
    private void InitializeComponent() {
        this.description.Dock = DockStyle.Fill;
        this.Controls.Add(this.description);
    }
   
    public bool ShowNavigatePrevious { get { return this.prev; } }
    public bool ShowNavigateNext { get { return this.next; } }
    public bool ShowNavigateFinish { get { return this.finish; } }
}

public class WizardPanelWithNavigation : Panel, IWizardPanel, IWizardNavigation {
    private bool prev;
    private bool next;
    private bool finish;
    private string name;
    private string nextPanel;
    private string prevPanel;
   
    private Label description = new Label();
   
    public WizardPanelWithNavigation(string name, string description, string prev, string next, bool finish) {
        this.prev = (prev != null);
        this.next = (next != null);
        this.finish = finish;
        this.description.Text = description;
        this.name = name;
        this.nextPanel = next;
        this.prevPanel = prev;
       
        InitializeComponent();
    }
   
    private void InitializeComponent() {
        this.description.Dock = DockStyle.Fill;
        this.Controls.Add(this.description);
    }
   
    public bool ShowNavigatePrevious { get { return this.prev; } }
    public bool ShowNavigateNext { get { return this.next; } }
    public bool ShowNavigateFinish { get { return this.finish; } }
   
    public bool SupportNamedNavigation { get { return true; } }
    public string NavigateName { get { return this.name; } }
    public string NavigatePreviousTarget { get { return this.prevPanel; } }
    public string NavigateNextTarget { get { return this.nextPanel; } }
}

public class WizardTestDialog : Form, IWizardDialog {
    private Panel topPanel = new Panel();
    private Panel bottomPanel = new Panel();

    private Button previousButton;
    private Button nextButton;
    private Button finishButton;
   
    private string title;

    public WizardTestDialog(string title) {
        this.title = title;

        InitializeComponent();
    }
   
    public Control NavigatePrevious {
        get {
            return previousButton;
        }
    }

    public Control NavigateNext {
        get {
            return nextButton;
        }
    }

    public Control NavigateFinish {
        get {
            return finishButton;
        }
    }
   
    public Control UIRoot {
        get {
            return topPanel;
        }
    }
   
    public bool Display {
        get {
            return this.Visible;
        }
        set {
            this.Visible = value;
        }
    }
   
    private void InitializeComponent() {
        // Create our large containers
        // Top for wizard
        // Bottom for navigation
        this.bottomPanel.Height = 30;
        this.bottomPanel.Dock = DockStyle.Bottom;
       
        this.topPanel.Dock = DockStyle.Fill;
       
        this.Text = title;
        this.Controls.AddRange(new Control[] { topPanel, bottomPanel });
       
        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;
       
        this.bottomPanel.Controls.AddRange(new Control[] { previousButton, nextButton, finishButton });
    }
}

public class WizardTester {
    [STAThread()]
    private static void Main(string[] args) {
        WizardController controller = 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);
    }
}

Published Friday, April 23, 2004 7:28 PM by Justin Rogers

Comments

No Comments

Leave a Comment

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