Click here to Skip to main content
15,880,503 members
Articles / Desktop Programming / Windows Forms

A Plug-in Wizard Framework

Rate me:
Please Sign up or sign in to vote.
4.82/5 (31 votes)
21 May 2008BSD7 min read 90.9K   1.2K   127  
A wizard framework that supports plug-ins for the wizard pages.
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Clifton.Wizard
{
	/// <summary>
	/// The four states of the wizard.
	/// </summary>
	public enum WizardState
	{
		Uninitialized,
		Start,
		Middle,
		End,
	}

	/// <summary>
	/// The plugin manager coordinates the index to the current 
	/// manager and isolates some of the details of managing the
	/// plugins.
	/// </summary>
	public class PluginManager
	{
		protected List<Plugin> pluginList;
		protected int position;
		protected WizardState state;

		/// <summary>
		/// Returns the current state of the wizard.
		/// </summary>
		public WizardState State
		{
			get { return state; }
		}

		/// <summary>
		/// True if the plugin validates itself, indicating that the
		/// "Next" button can be enabled.
		/// </summary>
		public bool IsValid
		{
			get { return pluginList[position].Instance.IsValid; }
		}

		/// <summary>
		/// Constructor.  Initializes the plugin list and state.
		/// </summary>
		public PluginManager()
		{
			pluginList = new List<Plugin>();
			position = -1;
			state = WizardState.Uninitialized;
		}

		/// <summary>
		/// Adds as assembly to the plugin list.
		/// </summary>
		/// <param name="assemblyPath">The full assembly path.</param>
		/// <param name="typeName">The qualifed [namespace].[class] name that is instantiated.</param>
		public void AddAssembly(string assemblyPath, string typeName)
		{
			Plugin plugin = new Plugin(assemblyPath, typeName);
			pluginList.Add(plugin);
		}

		/// <summary>
		/// Loads all plugin assemblies.
		/// </summary>
		public void LoadPlugins()
		{
			if (pluginList.Count == 0)
			{
				throw new ApplicationException("At least one plugin assembly must be added to the plugin manager's collection.");
			}

			LoadPluginAssemblies();
		}

		/// <summary>
		/// Initialize the wizard state.
		/// </summary>
		public void Initialize()
		{
			position = 0;
			SetState();
		}

		/// <summary>
		/// Returns to the previous wizard frame.
		/// </summary>
		public void Previous()
		{
			if (position == 0)
			{
				throw new ApplicationException("The wizard position cannnot be decremented.");
			}

			--position;
			SetState();
		}

		/// <summary>
		/// Calls the current plugin's OnNext method then increments the frame postion
		/// and updates the wizard state.
		/// </summary>
		public void Next()
		{
			if (position == pluginList.Count - 1)
			{
				throw new ApplicationException("The wizard position cannot be incremented.");
			}

			pluginList[position].Instance.OnNext();
			++position;
			SetState();
		}

		/// <summary>
		/// Calls the plugin's OnHelp method (if implemented).  The default behavior is to
		/// do nothing.
		/// </summary>
		public void OnHelp()
		{
			pluginList[position].Instance.OnHelp();
		}

		/// <summary>
		/// Calls the last plugin's OnNext method.
		/// </summary>
		public void Final()
		{
			if (position != pluginList.Count - 1)
			{
				throw new ApplicationException("Final can only be called on the last frame in the wizard plugin list.");
			}

			pluginList[position].Instance.OnNext();
		}

		/// <summary>
		/// Returns the controls specified by the plugin.
		/// </summary>
		public List<Control> GetControls()
		{
			Plugin plugin = pluginList[position];
			List<Control> controls = plugin.GetControls();

			return controls;
		}

		/// <summary>
		/// Hooks the plugin's UpdateStateEvent, allowing the plugin to
		/// notify our wizard controller that the wizard state needs to
		/// be updated.
		/// </summary>
		/// <param name="eventHandler">The event handler sinking the notification.</param>
		public void HookUpdateStateEvent(EventHandler eventHandler)
		{
			foreach (Plugin plugin in pluginList)
			{
				plugin.Instance.UpdateStateEvent += eventHandler;
			}
		}

		/// <summary>
		/// Loads each plugin.
		/// </summary>
		protected void LoadPluginAssemblies()
		{
			foreach (Plugin plugin in pluginList)
			{
				plugin.LoadAndCreate();
			}
		}

		/// <summary>
		/// Sets the wizard state flag.
		/// </summary>
		protected void SetState()
		{
			if (pluginList.Count - 1 == position)
			{
				state = WizardState.End;
			}
			else if (position == 0)
			{
				state = WizardState.Start;
			}
			else
			{
				state = WizardState.Middle;
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
Architect Interacx
United States United States
Blog: https://marcclifton.wordpress.com/
Home Page: http://www.marcclifton.com
Research: http://www.higherorderprogramming.com/
GitHub: https://github.com/cliftonm

All my life I have been passionate about architecture / software design, as this is the cornerstone to a maintainable and extensible application. As such, I have enjoyed exploring some crazy ideas and discovering that they are not so crazy after all. I also love writing about my ideas and seeing the community response. As a consultant, I've enjoyed working in a wide range of industries such as aerospace, boatyard management, remote sensing, emergency services / data management, and casino operations. I've done a variety of pro-bono work non-profit organizations related to nature conservancy, drug recovery and women's health.

Comments and Discussions