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(Control 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;
}
Control newPanel = wizardPanels[wizardIndex] as Control;
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;
}
}
Control newPanel = wizardPanels[wizardIndex] as Control;
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;
Control startPanel = wizardPanels[wizardIndex] as Control;
if ( startPanel != null ) {
InitPanel(startPanel);
}
wizardDialog.Display = true;
}
private void InitPanel(Control 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 : DesignablePanel {
protected string description = null;
protected Label lblDescription = new Label();
public WizardPanel(string description, bool prev, bool next, bool finish) {
this.prev = prev;
this.next = next;
this.finish = finish;
this.description = description;
InitializeComponent();
}
private void InitializeComponent() {
this.lblDescription.Dock = DockStyle.Fill;
this.lblDescription.Text = this.description;
this.Controls.Add(this.lblDescription);
}
}
public class WizardPanelWithNavigation : DesignablePanelWithNavigation {
protected string description = null;
protected Label lblDescription = new Label();
public WizardPanelWithNavigation(string name, string description, string prev, string next, bool finish) {
this.name = name;
this.nextPanel = next;
this.prevPanel = prev;
this.finish = finish;
this.description = description;
InitializeComponent();
}
private void InitializeComponent() {
this.lblDescription.Dock = DockStyle.Fill;
this.lblDescription.Text = this.description;
this.Controls.Add(this.lblDescription);
}
}
public class DesignablePanel : UserControl, IWizardPanel {
protected bool prev = false;
protected bool next = false;
protected bool finish = false;
public DesignablePanel() {
}
[Browsable(false)] public virtual bool ShowNavigatePrevious { get { return this.prev; } }
[Browsable(false)] public virtual bool ShowNavigateNext { get { return this.next; } }
[Browsable(false)] public virtual bool ShowNavigateFinish { get { return this.finish; } }
[Browsable(true)]
[Category("Wizard")]
[Description("Determines if the Previous button is activated when this panel is displayed")]
public virtual bool NavigatePrevious {
get {
return this.prev;
}
set {
this.prev = value;
}
}
[Browsable(true)]
[Category("Wizard")]
[Description("Determines if the Next button is activated when this panel is displayed")]
public virtual bool NavigateNext {
get {
return this.next;
}
set {
this.next = value;
}
}
[Browsable(true)]
[Category("Wizard")]
[Description("Determines if the Finish button is activated when this panel is displayed")]
public virtual bool NavigateFinish {
get {
return this.finish;
}
set {
this.finish = value;
}
}
}
public class DesignablePanelWithNavigation : DesignablePanel, IWizardNavigation {
protected string name = null;
protected string nextPanel = null;
protected string prevPanel = null;
public DesignablePanelWithNavigation() {
}
[Browsable(false)] public virtual bool SupportNamedNavigation { get { return (this.nextPanel != null || this.prevPanel != null); } }
[Browsable(false)] public virtual string NavigateName { get { return this.name; } }
[Browsable(false)] public virtual string NavigatePreviousTarget { get { return this.prevPanel; } }
[Browsable(false)] public virtual string NavigateNextTarget { get { return this.nextPanel; } }
[Browsable(false)] public override bool ShowNavigatePrevious { get { return this.prevPanel != null; } }
[Browsable(false)] public override bool ShowNavigateNext { get { return this.nextPanel != null; } }
[Browsable(false)]
public override bool NavigatePrevious {
get {
return ShowNavigatePrevious;
}
set { }
}
[Browsable(false)]
public override bool NavigateNext {
get {
return ShowNavigateNext;
}
set { }
}
[Browsable(true)]
[Category("Wizard")]
[Description("Sets the name of this wizard panel for navigation purposes. Each panel" +
"within a WizardController must have a unique name.")]
public virtual string PanelName {
get {
return this.name;
}
set {
this.name = value;
}
}
[Browsable(true)]
[Category("Wizard")]
[Description("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 virtual string NextTargetName {
get {
return this.nextPanel;
}
set {
this.nextPanel = value;
}
}
[Browsable(true)]
[Category("Wizard")]
[Description("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 virtual string PreviousTargetName {
get {
return this.prevPanel;
}
set {
this.prevPanel = value;
}
}
}
public class DesignableWizardDialog : Form, IWizardDialog {
protected Control previousButton;
protected Control nextButton;
protected Control finishButton;
protected Control uiRoot;
public DesignableWizardDialog() { }
[Browsable(false)] public virtual Control NavigatePrevious { get { return previousButton; } }
[Browsable(false)] public virtual Control NavigateNext { get { return nextButton; } }
[Browsable(false)] public virtual Control NavigateFinish { get { return finishButton; } }
[Browsable(false)] public virtual Control UIRoot { get { return uiRoot; } }
[Browsable(false)] public virtual bool Display { get { return this.Visible; } set { this.Visible = value; } }
[Browsable(true)]
[Category("Wizard")]
[Description("Set the control used for previous panel navigation")]
public virtual Control NavigatePreviousControl { get { return this.previousButton; } set { this.previousButton = value; } }
[Browsable(true)]
[Category("Wizard")]
[Description("Set the control used for previous panel navigation")]
public virtual Control NavigateNextControl { get { return this.nextButton; } set { this.nextButton = value; } }
[Browsable(true)]
[Category("Wizard")]
[Description("Set the control used for previous panel navigation")]
public virtual Control NavigateFinishControl { get { return this.finishButton; } set { this.finishButton = value; } }
[Browsable(true)]
[Category("Wizard")]
[Description("Sets the control where all panels will be displayed")]
public virtual Control UIRootControl { get { return this.uiRoot; } set { this.uiRoot = value; } }
}
public class WizardTestDialog : DesignableWizardDialog {
private Panel bottomPanel = new Panel();
private string title;
public WizardTestDialog(string title) {
this.title = title;
InitializeComponent();
}
private void InitializeComponent() {
// 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;
this.Controls.AddRange(new Control[] { this.uiRoot, this.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);
}
}