Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / Visual Basic

EnumGroupBox - a semi-automatic GroupBox control

Rate me:
Please Sign up or sign in to vote.
4.20/5 (10 votes)
3 May 20063 min read 64.1K   822   36  
A GroupBox automatically filled using Enums as templates.
using	System;
using	System.Windows.Forms;
using System.ComponentModel;        
using System.Reflection;
using System.Collections;

namespace	NEnumGroupBox
{
	public class EnumGroupBox	:	GroupBox
	{
		#region	Public Enums
		[Flags]
			public enum	ControlType
		{
			radioButton	=	0,
			checkBox	=	1
		}
		[Flags]
			public enum	BuildDirection
		{
			row_by_row	=	0,
			col_by_col	=	1
		}
		[Flags]
			public enum	CaptDescription
		{
			descNo	=	0,
			descYes =	1,
			descNotNull =	descYes << 1
		}
		#endregion
		#region	Constructor(s)
		public EnumGroupBox():base()
		{
			m_EnumHorizontalStep = 80;
			m_EnumVerticalStep = 24;
			m_EnumSingleHeight = 16;
			m_EnumSingleWidth	=	80;
			m_checkArgs	=	new	CheckArgs();
			m_Value	=	-1;
			m_cols = -1;
			m_rows = -1;
			m_EnumUpperLeft	=	new	System.Drawing.Point(8,	16);
			m_EnumStep = new System.Drawing.Size(m_EnumHorizontalStep, m_EnumVerticalStep);
			m_EnumSingleSize = new System.Drawing.Size(m_EnumSingleWidth,	m_EnumSingleHeight);
			m_AutoSize = false;
			m_BuildDirection = BuildDirection.row_by_row;
			m_numControls	=	-1;
			m_captDescription = CaptDescription.descNo;
			m_width = -1;
      m_height = -1;
			this.Text = "";
		}

		#endregion
		#region	Local	Variables
		private	CheckArgs	m_checkArgs;
		private	Enum m_SourceEnum;
		private ControlType m_ButtonType;
		private Type m_SourceEnumType;
		private	System.Drawing.Point m_EnumUpperLeft;
		private	System.Drawing.Size	m_EnumSingleSize;
		private	System.Drawing.Size	m_EnumStep;
		private	bool m_AutoSize;
		private	BuildDirection m_BuildDirection;
		private	bool m_noEvent;
		private	int	m_EnumHorizontalStep;
		private	int	m_EnumSingleHeight;
		private	int	m_EnumSingleWidth;
		private	int	m_EnumVerticalStep;
		private	int	m_Left;
		private	int	m_Top;
		private	int	m_Value;
		private	int	m_cols;
		private	int	m_rows;
		private	int	m_propCols;
		private	int	m_propRows;
		private	int	m_numControls;
		private int m_width;
		private int m_height;
		private ArrayList m_controlList;
		private Control[] m_controls;
		private	int[]	m_int_values;
		private	string m_Title;
		private	string[] m_names;
		private string[] m_description;
		private string[] m_caption;
		private CaptDescription m_captDescription;
		#endregion
		#region	Properties
		///	<summary>
		///	Summary	origin of captions
		///	</summary>
		[Description("Defines whether captions aren taken from DescriptionAttributes or from Item names")]
		public CaptDescription EnumCaptDescription
		{
			set
			{
				try 
				{
					checkRunTime();
					m_captDescription = value;
				}
				catch (System.Exception)
				{
					// throw;
					// if you allow runtime changes of this property, comment out 'throw;'
					// and write the corresponding code here
					cleanControls();
					m_captDescription = value;
					EnumSource(m_SourceEnum, m_ButtonType);
				}
			}
			get
			{
				return m_captDescription;
			}
		}
		///	<summary>
		///	Summary	number of	columns
		///	</summary>
		[Description("Defines the number of columns the EnumGroupBox should have. -1 means that the number is calculated if EnumAutoSize is True")]
		public int EnumCols
		{
			set
			{
				try 
				{
					checkRunTime();
					m_propCols = value;
				}
				catch (System.Exception)
				{
					// throw;
					// if you allow runtime changes of this property, comment out 'throw;'
					// and write the corresponding code here
					m_propCols = value;
					m_rows = -1;
					cleanControls();
					calcSize();
					EnumSource(m_SourceEnum, m_ButtonType);
				}
			}
			get
			{
				return m_propCols;
			}
		}
		///	<summary>
		///	Summary	number of	rows
		///	</summary>
		[Description("Defines the number of rows the EnumGroupBox should have. -1 means that the number is calculated if EnumAutoSize is True")]
		public int EnumRows
		{
			set
			{
				try 
				{
					checkRunTime();
					m_propRows = value;
				}
				catch (System.Exception)
				{
					 throw;
					// if you allow runtime changes of this property, comment out 'throw;'
					// and write the corresponding code here
				}
			}
			get
			{
				return m_propRows;
			}
		}
		///	<summary>
		///	Summary	defines	order	of building	controls
		///	</summary>
		[Description("Defines the order how the single EnumGroupBox controls are generated")]
		public BuildDirection	EnumBuildDirection
		{
			set
			{
				try 
				{
					checkRunTime();
					m_BuildDirection = value;
				}
				catch (System.Exception)
				{
					// throw;
					// if you allow runtime changes of this property, comment out 'throw;'
					// and write the corresponding code here
					cleanControls();
					m_BuildDirection = value;
					EnumSource(m_SourceEnum, m_ButtonType);
				}
			}
			get
			{
				return m_BuildDirection;
			}
		}
		///	<summary>
		///	Summary	defines	autosizing of	the	EnumGroupBox
		///	</summary>
		[Description("Defines whether the EnumGroupBox sizes itself depending on the contained controls")]
		public bool	EnumAutoSize
		{
			set
			{
				try 
				{
					checkRunTime();
					m_AutoSize = value;
				}
				catch (System.Exception)
				{
					// throw;
					// if you allow runtime changes of this property, comment out 'throw;'
					// and write the corresponding code here
					m_AutoSize = value;
					cleanControls();
					calcSize();
					EnumSource(m_SourceEnum, m_ButtonType);
				}
			}
			get
			{
				return m_AutoSize;
			}
		}
		///	<summary>
		///	Summary	define constellation from	outside
		///	</summary>
		public int Value
		{
			set	
			{
				if (value	!= m_Value)
				{
					// throw;
					// if you allow runtime changes of this property, comment out 'throw;'
					// and write the corresponding code here
					m_Value	=	value;
					showOptions();
					m_checkArgs.intValue = m_Value;
					EnumChanged(this,	m_checkArgs);
				}
			}
		}
		///	<summary>
		///	Summary	location of	the	upper	left control inside	the	EnumGroupBox
		///	</summary>
		[Description("Defines the position of the upper left control inside the EnumGroupBox")]
		public System.Drawing.Point	EnumUpperLeft
		{
			set
			{
				try 
				{
					checkRunTime();
					m_EnumUpperLeft	=	value;
				}
				catch (System.Exception)
				{
					throw;
					// if you allow runtime changes of this property, comment out 'throw;'
					// and write the corresponding code here
				}
			}
			get
			{
				return m_EnumUpperLeft;
			}
		}

		///	<summary>
		///	Summary	size of	a	control	inside the EnumGroupBox
		///	default: EnumStep
		///	</summary>
		[Description("Defines the size of	a	single control	inside the EnumGroupBox")]
		public System.Drawing.Size EnumSingleSize
		{
			set
			{
				try 
				{
					checkRunTime();
					m_EnumSingleSize = value;
					m_EnumSingleHeight = m_EnumSingleSize.Height;
					m_EnumSingleWidth	=	m_EnumSingleSize.Width;
				}
				catch (System.Exception)
				{
					throw;
					// if you allow runtime changes of this property, comment out 'throw;'
					// and write the corresponding code here
				}
			}
			get
			{
				return m_EnumSingleSize;
			}
		}
		///	<summary>
		///	Summary	offset of	the	second,	third, ... control
		///	</summary>
		[Description("Defines the distance between the single controls")]
		public System.Drawing.Size EnumStep
		{
			set
			{
				try 
				{
					checkRunTime();
					m_EnumStep = value;
					m_EnumHorizontalStep = m_EnumStep.Width;
					m_EnumVerticalStep = m_EnumStep.Height;
				}
				catch (System.Exception)
				{
					throw;
					// if you allow runtime changes of this property, comment out 'throw;'
					// and write the corresponding code here
				}
			}
			get	
			{
				return m_EnumStep;
			}
		}
		///	<summary>
		///	Summary	enum to	describe by	this EnumGroupBox
		///	</summary>
		public String[]	EnumCaptions
		{
			set
			{
				try 
				{
					checkRunTime();
					if (value == null)
									return;
					for(int i=0;i<value.Length;i++)
						if (i < m_caption.Length)
						{
							m_caption[i] = value[i];
							m_controls[i].Text=value[i];
						}
				}
				catch (System.Exception)
				{
					throw;
					// if you allow runtime changes of this property, comment out 'throw;'
					// and write the corresponding code here
				}
			}
		}
		#endregion
		#region	Public Methods
		///	<summary>
		///	Summary	enum and control type for this EnumGroupBox
		///	</summary>
		public bool EnumSource (object enumSource, ControlType buttonType)
		{
			m_SourceEnum = (Enum)enumSource;
			if (m_SourceEnum !=	null)
			{
				m_SourceEnumType = m_SourceEnum.GetType();
				string enumName	=	m_SourceEnumType.Name;
				m_ButtonType = buttonType;
				if (m_SourceEnumType ==	null)
					return false;
				Array	m_values = Enum.GetValues(m_SourceEnumType);
				if (m_names == null)
				{
					m_names	=	Enum.GetNames(m_SourceEnumType);
					m_description = new string[m_values.Length];
					m_caption = new string[m_values.Length];
					m_int_values = new int[m_values.Length];
					m_values.CopyTo(m_int_values,0);
					m_Value	=	m_int_values[getIndex(m_SourceEnum.ToString())];
					for(int i=0;i<m_description.Length;i++)
					{
						FieldInfo fi= m_SourceEnum.GetType().GetField(m_values.GetValue(i).ToString()); 
						DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
						if (attributes.Length > 0)
							m_description[i] = attributes[0].Description.ToString();
					}
				}
				m_controlList = new ArrayList();
				// retreive	the	name of	the	field	corresponding	to the actual	enum
				if (m_SourceEnumType.DeclaringType !=	null)
				{
					MemberInfo[] x = m_SourceEnumType.DeclaringType.GetMembers();
					for	(int i=0;i<x.Length;i++)
					{
						if (x[i].MemberType.Equals(MemberTypes.Property))
						{
							string z = x[i].ToString();
							string[] n = z.Split(' ');
							if (enumName.EndsWith(n[1]))
							{
								m_Title = null;
								DescriptionAttribute[] attributes;
								switch (m_captDescription)
								{
									case CaptDescription.descYes:
										attributes = (DescriptionAttribute[])m_SourceEnum.GetType().GetCustomAttributes(typeof(DescriptionAttribute), false);
										if (attributes.Length > 0)
											m_Title = attributes[0].Description.ToString();
										if (m_Title == null)
											m_Title = "";
										break;
									case CaptDescription.descNotNull:
										attributes = (DescriptionAttribute[])m_SourceEnum.GetType().GetCustomAttributes(typeof(DescriptionAttribute), false);
										if (attributes.Length > 0)
											m_Title = attributes[0].Description.ToString();
										if (m_Title == null)
											m_Title	=	x[i].Name;
										break;
									case CaptDescription.descNo:
										m_Title	=	x[i].Name;
										break;
								}
								break;
							}
						}
					}
				}
				else
				{
					m_Title	=	"???";
				}
				this.Text	=	m_Title;
				switch (buttonType)
				{
					case ControlType.checkBox:
						CreateCheckBoxes();
						break;
					case ControlType.radioButton:
						CreateRadioButtons();
						break;
				}
				return true;
			}
			return false;
		}
		#endregion
		#region	Local	Methods
		private bool checkRunTime()
		{
			if (m_Title == null)
				return true;
			System.Exception e = new System.Exception("Property can be set in Designer only!");
			throw(e);
		}
		private void cleanControls()
		{
			for (int i=0;i<m_controls.Length;i++)
			{
				this.Controls.Remove(m_controls[i]);
				m_controls[i] = null;
			}
			m_controls = null;
		}
		private void	CreateRadioButtons()
		{
			m_Top	=	m_EnumUpperLeft.Y;
			m_Left = m_EnumUpperLeft.X;
			if (m_numControls	== -1)
			{
				m_numControls	=	m_names.Length+1;
				calcSize();
			}
			for	(int i=0;i<m_names.Length;i++)
			{
				if (m_captDescription == CaptDescription.descNo)
					addControl(m_names[i], new RadioButton());
				else
					addControl(m_description[i], new RadioButton());
			}
			m_controls = new Control[m_controlList.Count];
			m_controlList.CopyTo(m_controls);
			m_controlList.Clear();
			m_controlList = null;
			showOptions();
		}
		private void	CreateCheckBoxes()
		{
			m_Top	=	m_EnumUpperLeft.Y;
			m_Left = m_EnumUpperLeft.X;
			if (m_numControls	== -1)
			{
				m_numControls	=	0;
				for	(int i=0;i<m_names.Length;i++)
				{
					if (m_int_values[i]	!= 0)
						m_numControls++;
				}
				calcSize();
			}
			for	(int i=0;i<m_names.Length;i++)
			{
				if (m_int_values[i]	!= 0)
				{
					if (m_captDescription == CaptDescription.descNo)
						addControl(m_names[i], new CheckBox());
					else
						addControl(m_description[i], new CheckBox());
				}
			}
			m_controls = new Control[m_controlList.Count];
			m_controlList.CopyTo(m_controls);
			m_controlList.Clear();
			m_controlList = null;
			showOptions();
		}
		private	void calcSize()
		{
			int	rem	=	0;
			if (m_width == -1)
			{
				m_width = this.Width;
				m_height = this.Height;
			}
			if (m_AutoSize)
			{
				if ((m_propCols	== -1) &&	(m_propRows	== -1))
				{
					m_cols = Math.DivRem(this.Width, m_EnumHorizontalStep, out rem);
					if (rem	!= 0)
						m_cols++;
					m_rows = Math.DivRem(m_numControls,	m_cols,	out	rem);
					if (rem	!= 0)
						m_rows++;
				}
				else if	(m_propRows	== -1)
				{
					m_cols = m_propCols;
					m_rows = Math.DivRem(m_numControls,	m_cols,	out	rem);
					if (rem	!= 0)
						m_rows++;
				}
				else if	(m_propCols	== -1)
				{
					m_rows = m_propRows;
					m_cols = Math.DivRem(m_numControls,	m_rows,	out	rem);
					if (rem	!= 0)
						m_cols++;
				}
				this.Height	=	m_EnumUpperLeft.Y	+	m_rows * m_EnumVerticalStep;
				this.Width = 2 * m_EnumUpperLeft.X + m_cols	*	m_EnumHorizontalStep;
			}
			else
			{
				this.Width = m_width;
				this.Height = m_height;
				m_cols = Math.DivRem(this.Width, m_EnumHorizontalStep, out rem);
				if (rem	!= 0)
					m_cols++;
				m_rows = Math.DivRem(m_numControls,	m_cols,	out	rem);
				if (rem	!= 0)
					m_rows++;
			}
		}
		private	void addControl(string enumName, Control chk)
		{
			int	i	=	getIndex(enumName);
			if (i	!= -1) //	emergency	brake, -1	should never appear
			{
				chk.Tag	=	 m_int_values[i];
				chk.Name = m_names[i];
				chk.Text = enumName;
				chk.TabStop	=	false;
				chk.Visible	=	true;
				chk.Size = new System.Drawing.Size(m_EnumSingleWidth,	m_EnumSingleHeight);
				chk.Location = new System.Drawing.Point(m_Left,	m_Top);
				// calculate location	for	next control
				if (m_BuildDirection ==	BuildDirection.row_by_row)
				{
					m_Left +=	m_EnumHorizontalStep;
					// perhaps new row
					if (m_Left > this.Width	-	m_EnumHorizontalStep)
					{
						m_Left = m_EnumUpperLeft.X;
						m_Top	+= m_EnumVerticalStep;
					}
				}
				else
				{
					m_Top	+= m_EnumVerticalStep;
					// perhaps new column
					if (m_Top	>	this.Height	-	m_EnumVerticalStep)
					{
						m_Top	=	m_EnumUpperLeft.Y;
						m_Left +=	m_EnumHorizontalStep;
					}
				}

				// add event handler
				if (chk	is CheckBox)
					((CheckBox)chk).CheckStateChanged	+=new	EventHandler(EnumCheckChanged);
				else if	(chk is	RadioButton)
					((RadioButton)chk).CheckedChanged	+=new	EventHandler(EnumRadioChanged);
				this.Controls.Add(chk);
				if (m_controlList.Count < i)
					m_controlList.Add(new CheckBox());
				m_controlList.Insert(i, chk);
				m_caption[i] = chk.Text;
			}
		}

		private	int	getIndex(string	enumName)
		{
			for	(int i=0;i<m_names.Length;i++)
			{
				if (m_names[i].Equals(enumName))
				{
					return i;
				}
				if (enumName.Equals(m_description[i]))
				{
					return i;
				}
			}
			return -1;
		}

		private	void showOptions()
		{
			// supress EnumChanged event to	be fired
			m_noEvent	=	true;
			foreach	(Control x in	this.Controls)
			{
				int	val	=	(int)x.Tag;
				if ((m_Value & val)	== val)
				{
					if (x	is CheckBox)
						((CheckBox)x).CheckState = CheckState.Checked;
					else if	(x is	RadioButton)
						((RadioButton)x).Checked = true;
				}
				else
				{
					if (x	is CheckBox)
						((CheckBox)x).CheckState = CheckState.Unchecked;
					else if	(x is	RadioButton)
						((RadioButton)x).Checked = false;
				}
			}
			// reactivate	EnumChanged	event
			m_noEvent	=	false;
		}
		#endregion
		#region	Local	Events
		private	void EnumCheckChanged(object sender, EventArgs e)
		{
			if (m_noEvent)
				return;
			CheckBox tst = (CheckBox)sender;
			if (tst.CheckState ==	CheckState.Checked)
			{
				m_Value	|= (int)(tst.Tag);
			}
			else if	(tst.CheckState	== CheckState.Unchecked)
			{
				m_Value	&= ~(int)(tst.Tag);
			}
			m_checkArgs.intValue = m_Value;
			EnumChanged(this,	m_checkArgs);
		}
		private	void EnumRadioChanged(object sender, EventArgs e)
		{
			if (m_noEvent)
				return;
			m_Value	=	(int)(((Control)sender).Tag);
			m_checkArgs.intValue = m_Value;
			EnumChanged(this,	m_checkArgs);
		}
		#endregion
		#region	Custom Events
		// The event arguments class,	derived	from EventArgs
		public class CheckArgs : EventArgs
		{
			private	object m_val;
			public CheckArgs()
			{
			}
			public object	Value
			{
				get
				{
					return m_val;
				}
			}
			// to	hold the 'Set	Property'	internal,	we use a different Property
			internal object	intValue
			{
				set
				{
					m_val	=	value;
				}
			}
		}
		// The delegate	procedure	we are assigning to	EnumGroupBox
		public delegate	void CheckHandler(object sender, CheckArgs a);
		// The Event Definition
		public event CheckHandler	EnumChanged;
		#endregion
	}
}

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


Written By
Web Developer
Germany Germany
Peter Schlang, working with computers since 1974
Developing mainly for newspapers since 1981, first as employee of ATEX
Freelancer since 1987
Preferred language is VB: Starting with VB 1.0 and VBDOS, up to VB.NET

Comments and Discussions