Click here to Skip to main content
15,881,173 members
Articles / Web Development / ASP.NET

ASP.NET Outlook Style Toolbar Control

Rate me:
Please Sign up or sign in to vote.
4.53/5 (11 votes)
10 Nov 20043 min read 121.9K   1.8K   68  
An outlook style toolbar control in ASP.NET
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Xml;
using System.Xml.Schema;
using System.IO;
using System.Collections;

[assembly:TagPrefix("CustomWebControls", "CustomWebControls")]

namespace CustomWebControls
{
	[Serializable()]
	public delegate void ToolbarButtonClicked (int Group, int Button);

	/// <summary>
	/// Summary description for Toolbar.
	/// </summary>
	[DefaultProperty("Text"), ToolboxData("<{0}:Toolbar runat=server></{0}:Toolbar>"), PersistChildren(true)]
	public class Toolbar : System.Web.UI.WebControls.WebControl, System.Web.UI.INamingContainer, System.Web.UI.IPostBackDataHandler
	{			
		public event ToolbarButtonClicked OnToolbarButtonClicked;

		private string SCHEMA_PATH = System.Web.HttpContext.Current.Request.MapPath("/CustomWebControls/Schema/Toolbar.xsd");

		// Default Property Values From XML Schema		
		private const string DEFAULT_SCROLLUP_IMAGE_PATH = "images/scrollup.gif";
		private const string DEFAULT_SCROLLDOWN_IMAGE_PATH = "images/scrolldown.gif";

		// XML Tags In Toolbar Definition
		private const string TOOLBAR_TAG				= "Toolbar";
		private const string TOOLBAR_GROUP_TAG			= "ToolbarGroup";
		private const string TOOLBAR_BUTTON_TAG			= "ToolbarButton";

		// XML Attributes In Toolbar Definition
		private const string ATTR_SCROLLUP_IMAGE_PATH	= "ScrollUpImagePath";
		private const string ATTR_SCROLLDOWN_IMAGE_PATH	= "ScrollDownImagePath";

		private const string ATTR_TOOLBAR_GROUP_CAPTION = "Caption";

		private const string ATTR_TOOLBAR_BUTTON_CAPTION= "Caption";
		private const string ATTR_TOOLBAR_BUTTON_IMAGE = "ImagePath";
		private const string ATTR_TOOLBAR_BUTTON_ALT = "Alt";

		// Public CSS Class Names
		public const string CSS_TOOLBAR					= "Toolbar";
		public const string CSS_TOOLBAR_GROUP_NORMAL	= "ToolbarGroupNormal";
		public const string CSS_TOOLBAR_GROUP_HOVER		= "ToolbarGroupHover";
		public const string CSS_TOOLBAR_BUTTON_TABLE	= "ToolbarButtonTable";
		public const string CSS_TOOLBAR_BUTTON_NORMAL	= "ToolbarButtonNormal";
		public const string CSS_TOOLBAR_BUTTON_HOVER	= "ToolbarButtonHover";
		public const string CSS_TOOLBAR_BUTTON_LABEL	= "ToolbarButtonLabel";

		// Internal CSS Class Prefixes
		private const string CSS_PREFIX_TOOLBAR_GROUP	= "ToolbarGroup";
		private const string CSS_PREFIX_TOOLBAR_BUTTON	= "ToolbarButton";
				
		[Bindable(true), Category("Appearance"), DefaultValue("")]
		public string ToolbarDefinitionFileName
		{
			set
			{
				string FileName = System.Web.HttpContext.Current.Request.MapPath(value);

				if (!System.IO.File.Exists(FileName))
				{					
					throw new Exception("File name " + FileName + " does not exist.");
				}

				LoadToolbarDef(FileName);		
			}
		}

		#region IPostBackDataHandler Members

		private void LoadToolbarDef(string ToolbarDefFileName)
		{
			XmlTextReader tr = new XmlTextReader(ToolbarDefFileName);
			XmlValidatingReader vr = new XmlValidatingReader(tr);

			vr.Schemas.Add("http://tempuri.org/Toolbar.xsd", SCHEMA_PATH);
			vr.ValidationType = ValidationType.Schema;
			vr.ValidationEventHandler += new ValidationEventHandler (ValidationHandler);
			
			XmlDocument Doc = new XmlDocument();
			Doc.Load(vr);

			vr.Close();
			tr.Close();			

			// Select Toolbar Node
			XmlNode ToolbarNodeDef = Doc.SelectNodes("/Toolbar")[0];
		
			_ToolbarDef = new ToolbarDef();

			// Fill In Properties Of Toolbar
			_ToolbarDef.ScrollUpImageSrc = ((ToolbarNodeDef.Attributes[ATTR_SCROLLUP_IMAGE_PATH] != null)?
				ToolbarNodeDef.Attributes[ATTR_SCROLLUP_IMAGE_PATH].Value:DEFAULT_SCROLLUP_IMAGE_PATH);

			_ToolbarDef.ScrollDownImageSrc = ((ToolbarNodeDef.Attributes[ATTR_SCROLLDOWN_IMAGE_PATH] != null)?
				ToolbarNodeDef.Attributes[ATTR_SCROLLDOWN_IMAGE_PATH].Value:DEFAULT_SCROLLDOWN_IMAGE_PATH);

			if (ToolbarNodeDef.ChildNodes == null)
			{
				return;
			}

			_ToolbarDef.Groups = new ToolbarGroupDef[ToolbarNodeDef.ChildNodes.Count];					

			for (int GroupIndex = 0; GroupIndex < _ToolbarDef.Groups.Length; GroupIndex++)
			{
				_ToolbarDef.Groups[GroupIndex] = new ToolbarGroupDef();
				
				ToolbarGroupDef NewGroup = _ToolbarDef.Groups[GroupIndex];
				
				XmlNode NewGroupNode = ToolbarNodeDef.ChildNodes[GroupIndex];

				NewGroup.Caption = NewGroupNode.Attributes[ATTR_TOOLBAR_GROUP_CAPTION].Value;
				
				// Construct Group Buttons
				if (ToolbarNodeDef.ChildNodes[GroupIndex].ChildNodes != null)
				{
					NewGroup.Buttons = new ToolbarButtonsDef[ToolbarNodeDef.ChildNodes[GroupIndex].ChildNodes.Count];

					for (int ButtonIndex = 0; ButtonIndex < NewGroup.Buttons.Length; ButtonIndex++)
					{
						NewGroup.Buttons[ButtonIndex] = new ToolbarButtonsDef();

						ToolbarButtonsDef NewButton = NewGroup.Buttons[ButtonIndex];

						XmlNode NewButtonNode = ToolbarNodeDef.ChildNodes[GroupIndex].ChildNodes[ButtonIndex];

						NewButton.Caption = NewButtonNode.Attributes[ATTR_TOOLBAR_BUTTON_CAPTION].Value;
						
						NewButton.ImagePath = NewButtonNode.Attributes[ATTR_TOOLBAR_BUTTON_IMAGE].Value;

						if (NewButtonNode.Attributes[ATTR_TOOLBAR_BUTTON_ALT] != null)
						{
							NewButton.Alt = NewButtonNode.Attributes[ATTR_TOOLBAR_BUTTON_ALT].Value;
						}						
					}
				}
			}
		}

		public static void ValidationHandler(object sender, ValidationEventArgs args)
		{
			return;
		}

		public void RaisePostDataChangedEvent()
		{
			// TODO:  Add Toolbar.RaisePostDataChangedEvent implementation
		}

		public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
		{
			// TODO:  Add Toolbar.LoadPostData implementation
			return false;
		}

		#endregion

		protected override object SaveViewState()
		{		
			Object[] SavedState = new Object[3];
			SavedState[0] = _ToolbarDef;
			SavedState[1] = _ActiveGroup;			
			SavedState[2] = base.SaveViewState ();

			return SavedState;
		}

		protected override void LoadViewState(object savedState)
		{
			Object[] SavedState = (Object[])(savedState);
			
			try
			{
				_ToolbarDef = (ToolbarDef) SavedState[0];			
			}
			catch (Exception)
			{
				_ToolbarDef = null;
			}

			try
			{			
				_ActiveGroup = (int) SavedState[1];
			}
			catch (Exception)
			{
				_ActiveGroup = 0;
			}

			base.LoadViewState (SavedState[2]);
		}		
				
		protected override void CreateChildControls()
		{			
			Controls.Clear();
			if (_ToolbarDef == null)
			{			
				return;
			}

			if (_ToolbarDef.Groups == null)
			{			
				return;
			}						

			// Register Client Script With The Container Page

			string Script = "<script language=\"javascript\">";
			Script += "function OnObjectMouseOut(Object, BaseClassPrefix)";
			Script += "{";								
			Script += "Object.className = BaseClassPrefix + \"Normal\";";
			Script += "}";
			
			Script += "function OnObjectMouseOver(Object, BaseClassPrefix)";
			Script += "{;Object.className = BaseClassPrefix + \"Hover\";}</script>";
			
			Page.RegisterClientScriptBlock(ID, Script);

			// TODO: Add New Table
			Table ToolbarTable = new Table();
			ToolbarTable.CssClass = CSS_TOOLBAR;
			ToolbarTable.CellPadding = 0;
			ToolbarTable.CellSpacing = 0;
			
			for (int GroupIndex = 0; GroupIndex < _ToolbarDef.Groups.Length; GroupIndex++)
			{	
				// TODO: Add New Group
				TableRow ToolbarGroupRow = new TableRow();
				ToolbarTable.Rows.Add(ToolbarGroupRow);

				TableCell ToolbarGroupCell = new TableCell();
				ToolbarGroupCell.HorizontalAlign = HorizontalAlign.Center;
				ToolbarGroupRow.Cells.Add(ToolbarGroupCell);
				
				Button GroupBtn = new Button();
				GroupBtn.CssClass = CSS_TOOLBAR_GROUP_NORMAL;
				GroupBtn.ID = "Group_" + GroupIndex;
				GroupBtn.Text = _ToolbarDef.Groups[GroupIndex].Caption;
				GroupBtn.Attributes.Add("onmouseover", "OnObjectMouseOver(this,\"" + CSS_PREFIX_TOOLBAR_GROUP + "\");");
				GroupBtn.Attributes.Add("onmouseout", "OnObjectMouseOut(this,\"" + CSS_PREFIX_TOOLBAR_GROUP + "\");");
				ToolbarGroupCell.Controls.Add(GroupBtn);

				if (_ToolbarDef.Groups[GroupIndex].Buttons == null)
				{
					continue;
				}

				if (GroupIndex != _ActiveGroup)
				{
					continue;
				}

				for (int ButtonIndex = 0; ButtonIndex < _ToolbarDef.Groups[GroupIndex].Buttons.Length; ButtonIndex++)
				{

					TableRow ToolbarButtonTableRow = new TableRow();
					ToolbarTable.Rows.Add(ToolbarButtonTableRow);

					TableCell ToolbarButtonTableCell = new TableCell();
					ToolbarButtonTableCell.HorizontalAlign = HorizontalAlign.Center;
					ToolbarButtonTableRow.Cells.Add(ToolbarButtonTableCell);

					Table ToolbarButtonTable = new Table();
					ToolbarButtonTable.CssClass = CSS_TOOLBAR_BUTTON_TABLE;
					ToolbarButtonTableCell.Controls.Add(ToolbarButtonTable);

					TableRow ToolbarButtonRow = new TableRow();
					ToolbarButtonTable.Rows.Add(ToolbarButtonRow);

					TableCell ToolbarButtonCell = new TableCell();
					ToolbarButtonRow.Cells.Add(ToolbarButtonCell);

					ImageButton ToolbarImage = new ImageButton();
					ToolbarImage.ImageUrl = _ToolbarDef.Groups[GroupIndex].Buttons[ButtonIndex].ImagePath;
					ToolbarImage.ID = "Button_" + GroupIndex + "_" + ButtonIndex;
					
					if (_ToolbarDef.Groups[GroupIndex].Buttons[ButtonIndex].Alt != null)
					{
						if (_ToolbarDef.Groups[GroupIndex].Buttons[ButtonIndex].Alt != String.Empty)
						{
							ToolbarImage.AlternateText = _ToolbarDef.Groups[GroupIndex].Buttons[ButtonIndex].Alt;
						}
					}

					ToolbarImage.CssClass = CSS_TOOLBAR_BUTTON_NORMAL;										
					ToolbarImage.Attributes.Add("onmouseover", "OnObjectMouseOver(this,\"" + CSS_PREFIX_TOOLBAR_BUTTON + "\");");
					ToolbarImage.Attributes.Add("onmouseout", "OnObjectMouseOut(this,\"" + CSS_PREFIX_TOOLBAR_BUTTON + "\");");
					ToolbarButtonCell.Controls.Add(ToolbarImage);

					LinkButton ButtonLabel = new LinkButton();
					ButtonLabel.CssClass = CSS_TOOLBAR_BUTTON_LABEL;
					ButtonLabel.ID = "Label_" + GroupIndex + "_" + ButtonIndex;
					ButtonLabel.Text = _ToolbarDef.Groups[GroupIndex].Buttons[ButtonIndex].Caption;										
					ToolbarButtonTableCell.Controls.Add(ButtonLabel);

					// Add A Gap Between Buttons
					ToolbarButtonTableCell.Controls.Add(new LiteralControl("<P>"));
				}

				// Add Empty Slot For Top Alignment
				TableRow EmptyRow = new TableRow();
				ToolbarTable.Rows.Add(EmptyRow);								
			}

			Controls.Add(ToolbarTable);
		}

		private ToolbarDef _ToolbarDef;
		private int _ActiveGroup = 0;		

		protected override bool OnBubbleEvent(object source, EventArgs args)
		{			
			Control SourceControl = (Control)source;
			string[] FragID = SourceControl.ID.Split(new char[]{'_'});

			if (FragID[0] == "Group")
			{
				_ActiveGroup = int.Parse(FragID[1]);
			}
			
			if ((FragID[0] == "Button")||(FragID[0] == "Label"))
			{
				if (OnToolbarButtonClicked != null)
				{
					OnToolbarButtonClicked(int.Parse(FragID[1]), int.Parse(FragID[2]));
				}
			}

			CreateChildControls();
			return base.OnBubbleEvent (source, args);
		}

	}

	[Serializable()]
	class ToolbarDef
	{
		public string ScrollUpImageSrc;
		public string ScrollDownImageSrc;
		public ToolbarGroupDef[] Groups;
	}

	[Serializable()]
	class ToolbarGroupDef
	{
		public string Caption;
		public ToolbarButtonsDef[] Buttons;
	}

	[Serializable()]
	class ToolbarButtonsDef
	{
		public string Caption;
		public string ImagePath;
		public string Alt;
	}
}

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
Software Developer (Senior) MixModes Inc. | Research In Motion
Canada Canada
Ashish worked for Microsoft for a number of years in Microsoft Visual Studio (Architect edition) and Windows Live division as a developer. Before that he was a developer consultant mainly involved in distributed service development / architecture. His main interests are distributed software architecture, patterns and practices and mobile device development.

Currently Ashish serves as a Technical Lead at RIM leading next generation BlackBerry media experience and also runs his own company MixModes Inc. specializing in .NET / WPF / Silverlight technologies. You can visit MixModes at http://mixmodes.com or follow it on Twitter @MixModes

In his free time he is an avid painter, hockey player and enjoys travelling. His blog is at: http://ashishkaila.serveblog.net

Comments and Discussions