Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

An XML- and State Machine-based Design of a WinForms Control

, 1 Dec 2002
Usage of state machine and comprehensive XML description of control helps its user to considerably simplify control handling code.
xmlstatemachinewfcontrol_src.zip
res
Mixed.gif
Show.gif
Hide.gif
EstoniaFlag.gif
Weather.gif
LatviaFlag.gif
LithuaniaFlag.gif
hand.cur
Lithuania0.gif
Estonia0.gif
Baltia.jpg
Latvia1.gif
Lithuania1.gif
Estonia1.gif
Latvia0.gif
NoFlag.gif
Raining.gif
Sunny.gif
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Reflection;


//
// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("OGCLib")]
[assembly: AssemblyDescription("This assembly contains classes for the open group control.")]
[assembly: AssemblyCompany("Igor Ladnik")]
[assembly: AssemblyProduct("Open Group Control")]

[assembly: AssemblyVersion("1.2.*")]

namespace OGCLib
{
	///////////////////////////////////////////////////////////////////////////////////
	// Enum Orientation
	///////////////////////////////////////////////////////////////////////////////////
	public enum Orientation
	{
		Horizontal = 0,
		Vertical   = 1,
	}
		
	///////////////////////////////////////////////////////////////////////////////////
	// Class OGControl
	///////////////////////////////////////////////////////////////////////////////////
	public class OGControl : UserControl
	{
		// Event/Delegate
		//					StateChangedEvent
		public delegate void StateChangedEventHandler(OGControl source, EventArgs ea);
		static public event  StateChangedEventHandler StateChangedEvent;

		//					ErrorEvent
		public delegate void ErrorEventHandler(OGControl source, ErrorEventArgs eea);
		static public event  ErrorEventHandler ErrorEvent;

		// Distance (in % of an coorespondent container form's client area size) 
		// between cursor and appropriate form's side to dock control to this side.
		const int dockingDistanceInPerCent = 20; 

		// Enums
		private enum Zone // defines hit test zones for docking
		{
			None		= 0,
			Top         = 1,
			Left        = 2,
			Right       = 4,
			Bottom      = 8,
			TopLeft     = Top+Left,
			TopRight    = Top+Right,
			BottomLeft  = Bottom+Left,
			BottomRight = Bottom+Right,
		}

		/////////////////////
		// Class Caption
		/////////////////////
		private struct Caption
		{
			// Variables
			internal int	   height;
			internal Rectangle rect;
			internal string	   text;
			internal Font	   font;
			internal FontStyle fontStyle;
			internal Color	   colorBack;
			internal Color	   colorBorder;
			internal Color	   colorText;
			internal bool	   clicked;
			internal float	   captionTextSize; 

			// METHODS
			public bool HitTest(MouseEventArgs mea)
			{
				return rect.Contains(new Point(mea.X, mea.Y));
			}

			// Draw caption
			public void Draw(Graphics grfx, Rectangle clipRect)
			{
				if (height > 0)
				{
					Rectangle rect0 = new Rectangle(rect.Left, rect.Top, 
						rect.Width-1, rect.Height-1);

					// Fill
					Brush brush = new SolidBrush(colorBack);
					grfx.FillRectangle(brush, rect0);
					
					// Text
					float indent = 2.0f;
					Font fontRegular = new Font(font.FontFamily, captionTextSize, fontStyle);
					SizeF textSizeF = grfx.MeasureString(text, fontRegular);
					SizeF rectSizeF = new SizeF(rect0.Width-indent, rect0.Height);
					if (rectSizeF.Width >= textSizeF.Width)
						grfx.DrawString(text, fontRegular, new SolidBrush(colorText), indent, 0);

					// Border
					grfx.DrawRectangle(new Pen(colorBorder, 1), rect0); 
				}
			}
		}

		// Variables
		protected ArrayList    alElement = null;  // collection of control's elements (type: IElement)
		protected ArrayList    alError = null;    // collection of error strings (type: string)
		protected string       xmlConfFileName;   // configuration XML file name
		private Hashtable	   htAssembly = null; // collection of loaded elements' assemblies:
		                                          //   string assemblyName -> Assembly assembly
		private ToolTip        toolTip = null;
		private Cursor         standardCursor = null;
		private Cursor         activeCursor = null;
		private IElement       hitElement = null;     // currently selected element
		private MouseEventArgs currentMea = null;
		private int			   controlStatesMax = 0;  // max number of the control's states
		private int[,]         aiControlState = null; // Control State matrix: 
		                                              //   [max number of the control's states, number of elements].
		                                              //   Contains each element states for each state of control.
		private int			   currentState = 0;      //   current control's state
		private Caption		   caption;
		private bool		   horizOrient;       // current and
		private bool           prevHorizOrient;   // previous orintation of docked control
		private bool		   rotate;            // indicates whether control's element should be rotated
		                                          //   on orientation change
		private int			   angle = 0;         // rotation angle
		private DockStyle      initDock;          // initial docking style
		
		// parameters for ghost image enabling while dragging control to redock it
		private bool           ghost = false;
		private Color          initBackColor;

		// CONSTRUCTOR
		public OGControl(string xmlConfFileName)
		{	
			this.xmlConfFileName = xmlConfFileName;

			toolTip = new ToolTip();	

			alElement = new ArrayList();
			alError = new ArrayList();
			htAssembly = new Hashtable();

			// Set background color to Transparent
			SetStyle(ControlStyles.SupportsTransparentBackColor, true);
			BackColor = Color.Transparent;
			standardCursor = Cursor.Current;

			// Create Configurator and initialize control's elements 
			//   with XML config. file
			ConfiguratorFactory(true);

			InitUpdateGeometry();

			caption.clicked = false;
			caption.text = Name;
			caption.font = Font;

			prevHorizOrient = true;
			horizOrient = prevHorizOrient;
	
			initBackColor = BackColor;

			UpdateAllElements();
		}

		// PROPERTIES
		public IElement HitElement 
		{
			get { return hitElement;  }
			set { hitElement = value; }
		}

		public int VisualElementsNumber 
		{
			get { return alElement.Count; }
		}

		public string ActiveCursorFileName
		{
			set 
			{
				if (null != activeCursor)
					activeCursor.Dispose();

				activeCursor = new Cursor(value);
			}
		}

		public int ControlStatesMax
		{
			get { return controlStatesMax;  }
			set { controlStatesMax = value; }
		}
		
		public int CurrentState
		{
			get { return currentState;  }
			set { currentState = value; }
		}

		public int Angle
		{
			get { return angle;  }
			set { angle = value; }
		}

		public DockStyle InitDock
		{
			set { initDock = value; }
		}

		public int CaptionHeight 
		{
			get { return caption.height;  }
			set { caption.height = value; }
		}

		internal bool Rotate
		{
			get { return rotate;  }
			set { rotate = value; }
		}

		internal int CaptionTextSize
		{
			set { caption.captionTextSize = (float)value; }
		}

		protected MouseEventArgs CurrentMea 
		{
			get { return currentMea; }
		}

		protected virtual int MaxErrorsNumInBase 
		{
			get { return (int)ErrorType.Count; }
		}

		private Rectangle CaptionRect 
		{
			get 
			{ 
				caption.rect = new Rectangle(ClientRectangle.Left,  ClientRectangle.Top,
					ClientRectangle.Width, CaptionHeight);
				return caption.rect;
			}
		}

		// INDEXERS

		// Get element by its index from control collection
		public virtual IElement this[int index]
		{
			get
			{
				if (alElement.Count > 0)
					return (IElement)alElement[index];

				return null;
			}
		}

		// Get element by its name from control collection
		public virtual IElement this[string name]
		{
			get 
			{
				if (alElement.Count > 0)
					foreach (IElement element in alElement)
						if (name == element.GetName())
							return element;
				
				return null;
			}
		}

		// Get element's state number by control's state number 
		//   and the element's id from Control State matrix
		public int this[int ctrlState, int elementId]
		{
			get 
			{ 
				try
				{
					return aiControlState[ctrlState, elementId];
				}
				catch
				{
					return -1;
				}
			}
		}

		// METHODS
		public virtual string GetErrorTag(int i)
		{
			try
			{
				return asErrorTag[i]; 
			}
			catch
			{
				return null;
			}
		}

		public virtual string GetErrorMessage(int i)
		{
			try
			{
				return (string)alError[i];
			}
			catch
			{
				return null;
			}
		}

		public void AddErrorMessage(string errorMessage)
		{
			alError.Add(errorMessage);
		}

		// Set a cell[ctrlState, visElemId] of Control State matrix
		public void SetMatrixElement(int ctrlState, int visElemId, int val)
		{
			if (null == aiControlState)
			{
				if (controlStatesMax > 0 && alElement.Count > 0)
				{
					aiControlState = new int[controlStatesMax, alElement.Count];

					// Initialize all cells with -1
					for (int i=0; i<controlStatesMax; i++)
						for (int j=0; j<alElement.Count; j++)
							aiControlState[i, j] = -1;	
				}
				else
					return;
			}

			aiControlState[ctrlState, visElemId] = val;	
		}

		// Get orintation based in docking style
		public Orientation GetOrientation()
		{
			return DockStyle.Top == Dock || DockStyle.Bottom == Dock 
				|| DockStyle.Fill == Dock
				? Orientation.Horizontal : Orientation.Vertical;
		}

		// Raise Error event
		public void OnError(ErrorEventArgs eea)
		{
			if (null != ErrorEvent)
				ErrorEvent(this, eea);
		}

		internal void CaptionStyle(Color colorBack, Color colorText, FontStyle fontStyle)
		{
			caption.colorBack   = colorBack;
			caption.colorText   = colorText;
			caption.colorBorder = caption.colorText;
			caption.fontStyle   = fontStyle;
		}

		// Create a new control's element (with dynamically loaded element assembly) 
		//   and add it to collection
		internal IElement AddElement(string type, string name, Point horizPosition, 
													Point vertPosition, Size size)
		{
			IElement element = null;

			string assemblyName = type + "Lib"; // Name convention for loaded element assemblies.
			                                    // The assemblies assumed in working directory.
			Assembly assembly = (Assembly)htAssembly[assemblyName]; 
			if (null == assembly)
			{
				// This assembly has not been loaded yet
				try
				{
					assembly = Assembly.Load(assemblyName);
					if (null == assembly)
						throw(new Exception());
						
					// Add newly loaded assembly to collection
					htAssembly.Add(assemblyName, assembly);
				}
				catch
				{
					// Load assembly error
					ErrorType errorType = ErrorType.LoadAssembly;
					string errorMessage = string.Format(GetErrorMessage((int)errorType), assemblyName);
					OnError(new ErrorEventArgs(ErrorSeverity.Error, errorMessage));
				}
			}

			if (null != assembly)
			{
				string className = assemblyName + ".Factory"; // name convention for Factory class 
				                                              //   in the assembly
				// Create instance of assembly's Factory class
				object factory = assembly.CreateInstance(className);
				
				if (null != factory)
					// Create control's element with assembly's Factory
					element = ((IFactory)factory).CreateElement(this);
			}

			if (null != element)
			{
				// Initialize newly creted element and add it to collection
				element.Initialize(name, horizPosition, vertPosition, size);
				alElement.Add(element);
			}
			
			return element;
		}	
		// In the above method, when an element assembly is loaded, to create an IElement object
		// it is possible to loop through the assembly's types (with Reflection technique) looking for a type
		// that implements IElement. But I opted for IFactory mechanismdue to the followng.
		// Although it's unlikely, several types in the assembly may implement IElement interface.
		// In this case the assembly may decide by itself which type instantiate. Factory mechanism resolves
		// this (almost pure theoretical case).
		
		// Factory to create Configurator object (to support Configurator-derived classes, if any
		protected virtual void ConfiguratorFactory(bool operationLoad)
		{
			Configurator configurator = 
				new Configurator(this, xmlConfFileName, operationLoad);
		}	

		protected IElement HitTest(MouseEventArgs mea)
		{
			IElement theLastInZOrderVisualElement = null;
			if (alElement.Count > 0)
				foreach (IElement element in alElement)
					if (element.HitTest(mea))
						theLastInZOrderVisualElement = element;

			return theLastInZOrderVisualElement;
		}

		// ToolTip support
		protected void ToolTipHandling(IElement element)
		{
			if (null == currentMea)
				return;

			if (MouseButtons.None == currentMea.Button)
			{
				// None mouse button is pressed
				string tip = ".";
				if (null != element)
				{
					// Set up the ToolTip text for the control
					tip = ConstructTip(element.GetName(), element.GetStateName());
				
					if (!toolTip.Active)
					{
						toolTip.Dispose();
						toolTip = new ToolTip();

						toolTip.AutoPopDelay = 5000;
						toolTip.InitialDelay = 1000;
						toolTip.ReshowDelay = 500;
					}			
					
					toolTip.Active = true;
				}
				else
					toolTip.Active = false;

				toolTip.SetToolTip(this, tip);
			}
		}
		
		private Orientation GetInitOrientation()
		{
			return DockStyle.Top == initDock || DockStyle.Bottom == initDock 
				|| DockStyle.Fill == initDock
				? Orientation.Horizontal : Orientation.Vertical;
		}

		// Convert a point to Parent Form coordinates
		private Point PointToParentClient(int x, int y)
		{
			Point ptAtControl = new Point(x, y);
			Point ptAtScreen  = PointToScreen(ptAtControl);
			return Parent.PointToClient(ptAtScreen);
		}

		private void InitUpdateGeometry()
		{
			if (alElement.Count > 0)
			{
				Orientation orientation = GetOrientation();
				if (GetInitOrientation() != orientation)
				{
					horizOrient = (Orientation.Horizontal == GetOrientation());
					TransposeRotate();
				}
			}
		}

		private void UpdateGeometry()	
		{
			if (prevHorizOrient != horizOrient && alElement.Count > 0)
				TransposeRotate();
		}

		private void TransposeRotate()	
		{
			if (rotate)
				angle = horizOrient ? 90 : -90;
			else
				angle = 0;

			foreach (IElement element in alElement)
				element.UpdateGeometry();
		}

		// Update current state of all elements
		private void UpdateAllElements()
		{
			if (alElement.Count > 0 && null != aiControlState)
				foreach (IElement element in alElement)
					element.SetCurrentState(this[currentState, element.GetId()]);

			Invalidate();
		}

		// Overriden  
		protected override void OnMouseDown(MouseEventArgs mea)
		{		
			currentMea = mea;

			if (MouseButtons.Left == mea.Button)
			{
				if (CaptionHeight > 0)
					caption.clicked = caption.HitTest(mea);

				if (!caption.clicked)
					hitElement = HitTest(mea);
			}

			base.OnMouseDown(mea);
		}

		protected override void OnMouseUp(MouseEventArgs mea)
		{
			GhostOff();

			currentMea = mea;

			// Check whether caption is clicked
			if (caption.clicked)
			{
				caption.clicked = caption.HitTest(mea);
				if (!caption.clicked)
					ChangeDockStyle(mea);
			}
			else
			{
				// Check whether visual object is clicked
				if (null != hitElement)
					// Mouse was down at hitElement
					if (MouseButtons.Left == mea.Button)
					{
						IElement element = HitTest(mea);
						if (null != element)
						{
							if (element == hitElement)
							{
								// Down and Up at the SAME Visual Elememt
								int newControlState = -1;
								if (GetAndAssertNewControlState(hitElement, ref newControlState))
									ChangeState(newControlState);
							}
						}
					}
			}

			Cursor.Current = standardCursor;
			caption.clicked = false;

			base.OnMouseUp(mea);
		}					
					
		protected override void OnMouseMove(MouseEventArgs mea)
		{
			currentMea = mea;
			IElement element = null;

			// Check whether caption is clicked
			if (caption.clicked)
			{
				GhostOn();
				ChangeDockStyle(mea);
			}
			else
			{
				if (!caption.HitTest(mea))
				{
					element = HitTest(mea);
					if (null != element)
					{
						int wouldBeNewControlState = -1;
						if (GetAndAssertNewControlState(element, ref wouldBeNewControlState))
							Cursor.Current = activeCursor;
					}
				}
			}

			ToolTipHandling(element);

			base.OnMouseMove(mea);
		}

		protected override void OnResize(EventArgs ea)
		{
			Invalidate(CaptionRect);
	
			base.OnResize(ea);
		}

		protected override void OnPaint(PaintEventArgs pea)
		{
			Graphics grfx = pea.Graphics;
	
			// Draw all visual elements. This block is called even in case 
			//   of ghost placeholde rectangle to make invisible elements 
			//   derived from standard controls, like e.g. combo box.
			if (alElement.Count > 0)
				foreach (IElement element in alElement)
					element.Draw(grfx, !ghost);

			if (ghost)
				DrawGhost(grfx); // draw ghost			
			else
				caption.Draw(grfx, pea.ClipRectangle);  // draw caption
		}
		
		private void DrawGhost(Graphics grfx)
		{
			grfx.Clear(Parent.BackColor);
				
			Color ghostColor = (Color.DarkGray == Parent.BackColor) 
				? Color.LightGray : Color.DarkGray;
									
			Pen pen = new Pen(ghostColor, 9);
			pen.LineJoin = LineJoin.Round;
			//pen.DashStyle = DashStyle.Dash; // uncomment for Dash style for a ghost rectangle
			grfx.DrawRectangle(pen, ClientRectangle);
		}

		private bool GetAndAssertNewControlState(IElement element, ref int newControlState)
		{
			bool br = false;
			if (null != element)
			{
				newControlState = element.GetNewControlState();
				if (newControlState != currentState &&
					newControlState != -1)
					br = true;
			}

			return br;
		}

		// Switch on ghost placeholder mode while dragging control with its caption
		private void GhostOn()
		{
			if (!ghost)
			{
				initBackColor = BackColor;
				BackColor = Parent.BackColor; 
				ghost = true;
			}

			Invalidate();
		}

		// Switch off ghost placeholder mode
		private void GhostOff()
		{
			if (ghost)
			{
				BackColor = initBackColor;
				ghost = false;
				Invalidate();
			}
		}
		
		// Actions to change dock style
		private void ChangeDockStyle(MouseEventArgs mea)
		{		
			if (DockStyle.Fill != Dock)
			{
				prevHorizOrient = (Orientation.Horizontal == GetOrientation());
				
				// Calculate new docking style according to given rules.
				// Hit point is converted to Parent client coordinates.
				CalculateDock(PointToParentClient(mea.X, mea.Y));	
				
				horizOrient = (Orientation.Horizontal == GetOrientation());
				UpdateGeometry();

				// Save changes to XML config. file
				ConfiguratorFactory(false);
			}
			else
				horizOrient = prevHorizOrient;
		}

		// Virtual

		// Actiona related to change control's state
		public virtual bool ChangeState(int newCurrentState)
		{
			bool br = false;
			if (-1 != newCurrentState)
			{
				int prevState = currentState;
				currentState = newCurrentState;
				if (prevState != currentState)
				{
					UpdateAllElements();

					// Virtual method (currently empty) to let derived control class add
					//   its specific actions, if required
					OnChangeState();

					if (null != StateChangedEvent)
						// Raise StateChanged event
						StateChangedEvent(this, new EventArgs());

					// Save changes to XML config. file
					ConfiguratorFactory(false);

					br = true;
				}
			}

			return br;
		}

		// Calculate new docking style according to given rules
		protected virtual void CalculateDock(
			Point position /*hit point converted to Parent client coordinates*/)
		{
			if (Parent.ClientRectangle.Contains(position))
			{
				Rectangle leftRect = new Rectangle(
					Parent.ClientRectangle.Left, Parent.ClientRectangle.Top,
					Parent.ClientRectangle.Left +  
					Parent.ClientSize.Width	* dockingDistanceInPerCent / 100,
					Parent.ClientRectangle.Bottom);
			
				Rectangle rightRect = new Rectangle(
					Parent.ClientRectangle.Right - 
					Parent.ClientSize.Width	* dockingDistanceInPerCent / 100,
					Parent.ClientRectangle.Top,
					Parent.ClientRectangle.Right, Parent.ClientRectangle.Bottom);

				Rectangle topRect = new Rectangle(
					Parent.ClientRectangle.Left, Parent.ClientRectangle.Top,
					Parent.ClientRectangle.Right,
					Parent.ClientRectangle.Top + 
					Parent.ClientSize.Height * dockingDistanceInPerCent / 100);

				Rectangle bottomRect = new Rectangle(
					Parent.ClientRectangle.Left, 
					Parent.ClientRectangle.Bottom - 
					Parent.ClientSize.Height * dockingDistanceInPerCent / 100,
					Parent.ClientRectangle.Right, Parent.ClientRectangle.Bottom);

				int dock = (int)Zone.None;

				if (topRect.Contains(position))
					dock += (int)Zone.Top;

				if (leftRect.Contains(position))
					dock += (int)Zone.Left;
			
				if (rightRect.Contains(position))
					dock += (int)Zone.Right;

				if (bottomRect.Contains(position))
					dock += (int)Zone.Bottom;

				switch ((Zone)dock)
				{
					case Zone.Top:    Dock = DockStyle.Top;    break;			
					case Zone.Left:   Dock = DockStyle.Left;   break;		
					case Zone.Right:  Dock = DockStyle.Right;  break;
					case Zone.Bottom: Dock = DockStyle.Bottom; break;

					case Zone.TopLeft:
						Dock = (position.X - Parent.ClientRectangle.Left <
							position.Y - Parent.ClientRectangle.Top)
							? DockStyle.Left : DockStyle.Top;
						break;

					case Zone.TopRight:
						Dock = (Parent.ClientRectangle.Right - position.X <
							position.Y - Parent.ClientRectangle.Top)
							? DockStyle.Right : DockStyle.Top;
						break;
	
					case Zone.BottomLeft:
						Dock = (position.X - Parent.ClientRectangle.Left <
							Parent.ClientRectangle.Bottom - position.Y)
							? DockStyle.Left : DockStyle.Bottom;
						break;
	
					case Zone.BottomRight: 
						Dock = (Parent.ClientRectangle.Right  - position.X <
							Parent.ClientRectangle.Bottom - position.Y)
							? DockStyle.Right : DockStyle.Bottom;
						break;
				}
			}
		}

		// Allow derived control class to add its specific actions, if required
		protected virtual void OnChangeState()
		{
		}

		// Allow derived control class to construct element tips based on
		//   the element name and state
		protected virtual string ConstructTip(string visualElementName, string stateName)
		{
			return visualElementName;
		}
	
		// Read Only Error Tag Variable. Correspond to those in OGCErrorMessages.xml file.
		private readonly string[] asErrorTag = 
		{
			"ErrorMessages",
			"Picture",
			"LoadConfigFile",
			"ProcessNode",
			"ReadingTag",
			"WritingTag",
			"TagState",
			"LoadAssembly",
			"StateTransition",
			"ControlStatesMatrix",
		};
	}

	///////////////////////////////////////////////////////////////////////////////////
	// Enum ErrorType. Corresponds to asErrorTag array.
	///////////////////////////////////////////////////////////////////////////////////
	public enum ErrorType
	{
		None				= -1,
		ErrorMessages		=  0,
		Picture				=  1,
		LoadConfigFile		=  2,
		ProcessNode			=  3,
		ReadingTag			=  4,
		WritingTag			=  5,
		TagState			=  6,
		LoadAssembly		=  7,
		StateTransition		=  8,
		ControlStatesMatrix	=  9,
		Count				= 10,
	}

	///////////////////////////////////////////////////////////////////////////////////
	// Enum ErrorSeverity
	///////////////////////////////////////////////////////////////////////////////////
	public enum ErrorSeverity
	{
		None    =  0,
		Warning =  1,
		Error   =  2,
	}

	///////////////////////////////////////////////////////////////////////////////////
	// class ErrorEventArgs
	///////////////////////////////////////////////////////////////////////////////////
	public class ErrorEventArgs
	{
		// Variables
		public ErrorSeverity errorSeverity = ErrorSeverity.None;
		public string        errorMessage = null;

		// Constructor
		public ErrorEventArgs(ErrorSeverity errorSeverity, string errorMessage)
		{
			this.errorSeverity = errorSeverity;
			this.errorMessage = errorMessage;
		}
	}

	///////////////////////////////////////////////////////////////////////////////////
	// Interface IElement
	//   Each element of control has to implement this interface.
	///////////////////////////////////////////////////////////////////////////////////
	public interface IElement
	{
		// Initialize the element
		void Initialize(string name, Point horizPosition, Point vertPosition, Size size);
	
		// Set State Transition matrix cell
		void SetControlStateTransitionElement(int currCtrlState,  // current control's state (row)
											  int currState,      // current element's state (column)
											  int nextCtrlState); // next control's state (value)
		
		// Add state to the element
		int AddState(string name,           
			         string pictureName,  // name of state's picture file
			         string ext);         // extension state's of picture file 
		
		// Get new control's state on activation of the element
		int GetNewControlState();               
		
		// Set current element's state according to a control's state
		void SetCurrentState(int currentControlState); 

		// true -  for pictorial elements (like OGCVisualElement), 
		// false - for elements derived from standard (like OGCComboBox)
		bool HasImage();
		
		// Get element name
		string GetName();

		// Get element id (currently, serial number in the control's elements collection)
		int GetId();

		// Get name of the current state of the element
		string GetStateName();

		// Get number of possible changes in control, 
		// e.g., number of items in list - for combo box
		//       1 - for press button and visual element
		int GetNextStatesNum();

		// Update geometry of the element according to current orientation
		void UpdateGeometry();
		
		// Indicate whether cursor position is currently over the element
		bool HitTest(MouseEventArgs mea);
		
		// Draw the element
		void Draw(Graphics grfx, 
			      bool show);	// show/hide the element
	}

	///////////////////////////////////////////////////////////////////////////////////
	// Interface IFactory
	//   implemented by each loadable element assembly in order to instantiate 
	//   correspondent element.
	///////////////////////////////////////////////////////////////////////////////////
	public interface IFactory
	{
		IElement CreateElement(OGControl ogControl);
	}
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Igor Ladnik
Architect
Israel Israel


  • Nov 2010: Code Project Contests - Windows Azure Apps - Winner
  • Feb 2011: Code Project Contests - Windows Azure Apps - Grand Prize Winner

Follow on   LinkedIn

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150327.1 | Last Updated 2 Dec 2002
Article Copyright 2002 by Igor Ladnik
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid