Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / C#

Themed Windows XP style Explorer Bar

Rate me:
Please Sign up or sign in to vote.
4.96/5 (471 votes)
6 Oct 200515 min read 1.9M   72.6K   1.1K  
A fully customizable Windows XP style Explorer Bar that supports Windows XP themes and animated expand/collapse with transparency.
/*
 * Copyright � 2004-2005, Mathew Hall
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 *    - Redistributions of source code must retain the above copyright notice, 
 *      this list of conditions and the following disclaimer.
 * 
 *    - Redistributions in binary form must reproduce the above copyright notice, 
 *      this list of conditions and the following disclaimer in the documentation 
 *      and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 */


using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Xml.Serialization;


namespace XPExplorerBar
{
	#region TaskPane
	
	/// <summary>
	/// A ScrollableControl that can contain Expandos
	/// </summary>
	[ToolboxItem(true),
	DesignerAttribute(typeof(TaskPaneDesigner))]
	public class TaskPane : ScrollableControl, ISupportInitialize
	{
		#region Event Handlers

		/// <summary>
		/// Occurs when an Expando is added to the TaskPane
		/// </summary>
		public event ExpandoEventHandler ExpandoAdded; 

		/// <summary>
		/// Occurs when an Expando is removed from the TaskPane
		/// </summary>
		public event ExpandoEventHandler ExpandoRemoved; 

		/// <summary>
		/// Occurs when a value in the CustomSettings proterty changes
		/// </summary>
		public event EventHandler CustomSettingsChanged;

		#endregion
			
		
		#region Class Data
		
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		/// <summary>
		/// Internal list of Expandos contained in the TaskPane
		/// </summary>
		private TaskPane.ExpandoCollection expandoCollection;
		
		/// <summary>
		/// System defined settings for the TaskBar
		/// </summary>
		private ExplorerBarInfo systemSettings;

		/// <summary>
		/// Specifies whether the TaskPane is currently initialising
		/// </summary>
		private bool initialising;

		/// <summary>
		/// Specifies whether the TaskPane and its children should render 
		/// themselves using a theme similar to the Windows XP Classic theme
		/// </summary>
		private bool classicTheme;
		
		/// <summary>
		/// Specifies whether the TaskPane and its children should render 
		/// themselves using a non-official Windows XP theme
		/// </summary>
		private bool customTheme;

		/// <summary>
		/// A Rectangle that specifies the size and location of the watermark
		/// </summary>
		private Rectangle watermarkRect;

		/// <summary>
		/// Specifies whether the TaskPane is currently performing a 
		/// layout operation
		/// </summary>
		private bool layout;

		/// <summary>
		/// 
		/// </summary>
		private int beginUpdateCount;

		/// <summary>
		/// Specifies the custom settings for the TaskPane
		/// </summary>
		private TaskPaneInfo customSettings;

		#endregion


		#region Constructor

		/// <summary>
		/// Initializes a new instance of the TaskPane class with default settings
		/// </summary>
		public TaskPane()
		{
			// This call is required by the Windows.Forms Form Designer.
			components = new System.ComponentModel.Container();

			// set control styles
			this.SetStyle(ControlStyles.DoubleBuffer, true);
			this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
			this.SetStyle(ControlStyles.UserPaint, true);
			this.SetStyle(ControlStyles.ResizeRedraw, true);
			this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);

			this.expandoCollection = new TaskPane.ExpandoCollection(this);

			// get the system theme settings
			this.systemSettings = ThemeManager.GetSystemExplorerBarSettings();

			this.customSettings = new TaskPaneInfo();
			this.customSettings.TaskPane = this;
			this.customSettings.SetDefaultEmptyValues();

			this.BackColor = this.systemSettings.TaskPane.GradientStartColor;
			this.BackgroundImage = this.BackImage;

			this.classicTheme = false;
			this.customTheme = false;

			// size
			int width = (this.systemSettings.TaskPane.Padding.Left + 
				this.systemSettings.TaskPane.Padding.Right + 
				this.systemSettings.Header.BackImageWidth);
			int height = width;
			this.Size = new Size(width, height);

			// setup sutoscrolling
			this.AutoScroll = false;
			this.AutoScrollMargin = new Size(this.systemSettings.TaskPane.Padding.Right, 
				this.systemSettings.TaskPane.Padding.Bottom);

			// Listen for changes to the parent
			this.ParentChanged += new EventHandler(this.OnParentChanged);

			this.beginUpdateCount = 0;

			this.initialising = false;
			this.layout = false;
		}

		#endregion


		#region Methods

		#region Appearance

		/// <summary>
		/// Forces the TaskPane and all it's Expandos to use a theme
		/// equivalent to Windows XPs classic theme 
		/// </summary>
		public void UseClassicTheme()
		{
			this.classicTheme = true;
			this.customTheme = false;
			
			ExplorerBarInfo settings = ThemeManager.GetSystemExplorerBarSettings();
			settings.UseClassicTheme();

			this.systemSettings.Dispose();
			this.systemSettings = null;

			this.SystemSettings = settings;
		}


		/// <summary>
		/// Forces the TaskPane and all it's Expandos to use the 
		/// specified theme
		/// </summary>
		/// <param name="stylePath">The path to the custom 
		/// shellstyle.dll to use</param>
		public void UseCustomTheme(string stylePath)
		{
			this.customTheme = true;
			this.classicTheme = false;
			
			ExplorerBarInfo settings = ThemeManager.GetSystemExplorerBarSettings(stylePath);

			this.systemSettings.Dispose();
			this.systemSettings = null;

			this.SystemSettings = settings;
		}


		/// <summary>
		/// Forces the TaskPane and all it's Expandos to use the 
		/// current system theme
		/// </summary>
		public void UseDefaultTheme()
		{
			this.customTheme = false;
			this.classicTheme = false;
			
			ExplorerBarInfo settings = ThemeManager.GetSystemExplorerBarSettings();

			this.systemSettings.Dispose();
			this.systemSettings = null;

			this.SystemSettings = settings;
		}

		#endregion

		#region Dispose

		/// <summary> 
		/// Releases the unmanaged resources used by the TaskPane and 
		/// optionally releases the managed resources
		/// </summary>
		/// <param name="disposing">True to release both managed and unmanaged 
		/// resources; false to release only unmanaged resources</param>
		protected override void Dispose( bool disposing )
		{
			if (disposing)
			{
				if (components != null)
				{
					components.Dispose();
				}

				if (this.systemSettings != null)
				{
					this.systemSettings.Dispose();
				}
			}

			base.Dispose(disposing);
		}

		#endregion

		#region Expandos

		/// <summary>
		/// Collaspes all the Expandos contained in the TaskPane
		/// </summary>
		// suggested by: PaleyX (jmpalethorpe@tiscali.co.uk)
		//               03/06/2004
		//               v1.1
		public void CollapseAll()
		{
			foreach (Expando expando in this.Expandos)
			{
				expando.Collapsed = true;
			}
		}


		/// <summary>
		/// Expands all the Expandos contained in the TaskPane
		/// </summary>
		// suggested by: PaleyX (jmpalethorpe@tiscali.co.uk)
		//               03/06/2004
		//               v1.1
		public void ExpandAll()
		{
			foreach (Expando expando in this.Expandos)
			{
				expando.Collapsed = false;
			}
		}


		/// <summary>
		/// Collaspes all the Expandos contained in the TaskPane, 
		/// except for the specified Expando which is expanded
		/// </summary>
		/// <param name="expando">The Expando that is to be expanded</param>
		// suggested by: PaleyX (jmpalethorpe@tiscali.co.uk)
		//               03/06/2004
		//               v1.1
		public void CollapseAllButOne(Expando expando)
		{
			foreach (Expando e in this.Expandos)
			{
				if (e != expando)
				{
					e.Collapsed = true;
				}
				else
				{
					expando.Collapsed = false;
				}
			}
		}

		#endregion

		#region ISupportInitialize Members

		/// <summary>
		/// Signals the TaskPane that initialization is starting
		/// </summary>
		public void BeginInit()
		{
			this.initialising = true;
		}


		/// <summary>
		/// Signals the TaskPane that initialization is complete
		/// </summary>
		public void EndInit()
		{
			this.initialising = false;

			this.DoLayout();
		}


		/// <summary>
		/// Gets whether the TaskPane is currently initialising
		/// </summary>
		[Browsable(false)]
		public bool Initialising
		{
			get
			{
				return this.initialising;
			}
		}

		#endregion

		#region Layout

		// fix: Added BeginUpdate() and EndUpdate() so that DoLayout() 
		//      isn't called everytime something happens with Expandos
		//      Brian Nottingham (nottinbe@slu.edu)
		//      22/12/2004
		//      v3.0
		
		/// <summary>
		/// Prevents the TaskPane from drawing until the EndUpdate method is called
		/// </summary>
		public void BeginUpdate()
		{
			this.beginUpdateCount++;
		}


		/// <summary>
		/// Resumes drawing of the TaskPane after drawing is suspended by the 
		/// BeginUpdate method
		/// </summary>
		public void EndUpdate()
		{
			this.beginUpdateCount = Math.Max(this.beginUpdateCount--, 0);

			if (beginUpdateCount == 0)
			{
				this.DoLayout(true);
			}
		}


		/// <summary>
		/// Forces the TaskPane to apply layout logic to child Expandos, 
		/// and adjusts the Size and Location of the Expandos if necessary
		/// </summary>
		public void DoLayout()
		{
			this.DoLayout(false);
		}


		// fix: Added DoLayout(bool performRealLayout) to improve 
		//      TaskPane scroll behavior
		//      Jewlin (jewlin88@hotmail.com)
		//      22/10/2004
		//      v3.0

		/// <summary>
		/// Forces the TaskPane to apply layout logic to child Expandos, 
		/// and adjusts the Size and Location of the Expandos if necessary
		/// </summary>
		/// <param name="performRealLayout">true to execute pending layout 
		/// requests; otherwise, false</param>
		public void DoLayout(bool performRealLayout)
		{
			// fix: take into account beginUpdateCount
			//      Brian Nottingham (nottinbe@slu.edu)
			//      22/12/2004
			//      v3.0
			//if (this.layout)
			if (this.layout || this.beginUpdateCount > 0)
			{
				return;
			}

			this.layout = true;
			
			// stop the layout engine
			this.SuspendLayout();
			
			Expando e;
			Point p;
			
			// work out how wide to make the controls, and where
			// the top of the first control should be
			int y = this.DisplayRectangle.Y + this.Padding.Top;
			int width = this.ClientSize.Width - this.Padding.Left - this.Padding.Right;

			// for each control in our list...
			for (int i=0; i<this.Expandos.Count; i++)
			{
				e = this.Expandos[i];

				// go to the next expando if this one is invisible and 
				// it's parent is visible
				if (!e.Visible && e.Parent != null && e.Parent.Visible)
				{
					continue;
				}

				p = new Point(this.Padding.Left, y);

				// set the width and location of the control
				e.Location = p;
				e.Width = width;

				// update the next starting point
				y += e.Height + this.Padding.Bottom;
			}

			// restart the layout engine
			this.ResumeLayout(performRealLayout);

			this.layout = false;
		}


		/// <summary>
		/// Calculates where the specified Expando should be located
		/// </summary>
		/// <returns>A Point that specifies where the Expando should 
		/// be located</returns>
		protected internal Point CalcExpandoLocation(Expando target)
		{
			if (target == null)
			{
				throw new ArgumentNullException("target");
			}

			int targetIndex = this.Expandos.IndexOf(target);

			Expando e;
			Point p;
			
			int y = this.DisplayRectangle.Y + this.Padding.Top;
			int width = this.ClientSize.Width - this.Padding.Left - this.Padding.Right;

			for (int i=0; i<targetIndex; i++)
			{
				e = this.Expandos[i];

				if (!e.Visible)
				{
					continue;
				}

				p = new Point(this.Padding.Left, y);
				y += e.Height + this.Padding.Bottom;
			}
			
			return new Point(this.Padding.Left, y);
		}


		/// <summary>
		/// Updates the layout of the Expandos while in design mode, and 
		/// adds/removes Expandos from the ControlCollection as necessary
		/// </summary>
		internal void UpdateExpandos()
		{
			if (this.Expandos.Count == this.Controls.Count)
			{
				// make sure the the expandos index in the ControlCollection 
				// are the same as in the ExpandoCollection (indexes in the 
				// ExpandoCollection may have changed due to the user moving 
				// them around in the editor)
				this.MatchControlCollToExpandoColl();				
				
				return;
			}

			// were any expandos added
			if (this.Expandos.Count > this.Controls.Count)
			{
				// add any extra expandos in the ExpandoCollection to the 
				// ControlCollection
				for (int i=0; i<this.Expandos.Count; i++)
				{
					if (!this.Controls.Contains(this.Expandos[i]))
					{
						this.OnExpandoAdded(new ExpandoEventArgs(this.Expandos[i]));
					}
				}
			}
			else
			{
				// expandos were removed
				int i = 0;
				Expando expando;

				// remove any extra expandos from the ControlCollection
				while (i < this.Controls.Count)
				{
					expando = (Expando) this.Controls[i];
					
					if (!this.Expandos.Contains(expando))
					{
						this.OnExpandoRemoved(new ExpandoEventArgs(expando));
					}
					else
					{
						i++;
					}
				}
			}
		}


		/// <summary>
		/// Make sure the the expandos index in the ControlCollection 
		/// are the same as in the ExpandoCollection (indexes in the 
		/// ExpandoCollection may have changed due to the user moving 
		/// them around in the editor or calling ExpandoCollection.Move())
		/// </summary>
		internal void MatchControlCollToExpandoColl()
		{
			this.SuspendLayout();
				
			for (int i=0; i<this.Expandos.Count; i++)
			{
				this.Controls.SetChildIndex(this.Expandos[i], i);
			}

			this.ResumeLayout(false);
				
			this.DoLayout(true);

			this.Invalidate(true);
		}


		/// <summary>
		/// Performs the work of scaling the entire control and any child controls
		/// </summary>
		/// <param name="dx">The ratio by which to scale the control horizontally</param>
		/// <param name="dy">The ratio by which to scale the control vertically</param>
		protected override void ScaleCore(float dx, float dy)
		{
			//base.ScaleCore (dx, dy);
		}

		#endregion

		#endregion


		#region Properties

		#region Colors

		/// <summary>
		/// Gets the first color of the TaskPane's background gradient fill.
		/// </summary>
		[Browsable(false)]
		protected Color GradientStartColor
		{
			get
			{
				if (this.CustomSettings.GradientStartColor != Color.Empty)
				{
					return this.CustomSettings.GradientStartColor;
				}

				return this.systemSettings.TaskPane.GradientStartColor;
			}
		}


		/// <summary>
		/// Gets the second color of the TaskPane's background gradient fill.
		/// </summary>
		[Browsable(false)]
		protected Color GradientEndColor
		{
			get
			{
				if (this.CustomSettings.GradientEndColor != Color.Empty)
				{
					return this.CustomSettings.GradientEndColor;
				}

				return this.systemSettings.TaskPane.GradientEndColor;
			}
		}


		/// <summary>
		/// Gets the direction of the TaskPane's background gradient fill.
		/// </summary>
		[Browsable(false)]
		protected LinearGradientMode GradientDirection
		{
			get
			{
				if (this.CustomSettings.GradientStartColor != Color.Empty && 
					this.CustomSettings.GradientEndColor != Color.Empty)
				{
					return this.CustomSettings.GradientDirection;
				}

				return this.systemSettings.TaskPane.GradientDirection;
			}
		}

		#endregion

		#region Expandos

		/// <summary>
		/// A TaskPane.ExpandoCollection representing the collection of 
		/// Expandos contained within the TaskPane
		/// </summary>
		[Category("Behavior"),
		DefaultValue(null), 
		Description("The Expandos contained in the TaskPane"), 
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
		Editor(typeof(ExpandoCollectionEditor), typeof(UITypeEditor))]
		public TaskPane.ExpandoCollection Expandos
		{
			get
			{
				return this.expandoCollection;
			}
		}


		/// <summary>
		/// A Control.ControlCollection representing the collection of 
		/// controls contained within the control
		/// </summary>
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public new Control.ControlCollection Controls
		{
			get
			{
				return base.Controls;
			}
		}

		#endregion

		#region Images

		/// <summary>
		/// Gets the Image used as the TaskPane's background
		/// </summary>
		protected Image BackImage
		{
			get
			{
				if (this.CustomSettings.BackImage != null)
				{
					return this.CustomSettings.BackImage;
				}

				return this.systemSettings.TaskPane.BackImage;
			}
		}


		/// <summary>
		/// Gets how the TaskPane's background Image is to be drawn
		/// </summary>
		protected ImageStretchMode StretchMode
		{
			get
			{
				if (this.CustomSettings.BackImage != null)
				{
					return this.CustomSettings.StretchMode;
				}

				return this.systemSettings.TaskPane.StretchMode;
			}
		}


		/// <summary>
		/// Gets the Image that is used as a watermark in the TaskPane's 
		/// client area
		/// </summary>
		protected Image Watermark
		{
			get
			{
				if (this.CustomSettings.Watermark != null)
				{
					return this.CustomSettings.Watermark;
				}

				return this.systemSettings.TaskPane.Watermark;
			}
		}


		/// <summary>
		/// Gets the alignment of the TaskPane's watermark
		/// </summary>
		protected ContentAlignment WatermarkAlignment
		{
			get
			{
				if (this.CustomSettings.Watermark != null)
				{
					return this.CustomSettings.WatermarkAlignment;
				}

				return this.systemSettings.TaskPane.WatermarkAlignment;
			}
		}

		#endregion

		#region Padding

		/// <summary>
		/// Gets the amount of space between the border and the 
		/// Expando's along each side of the TaskPane.
		/// </summary>
		protected Padding Padding
		{
			get
			{
				if (this.CustomSettings.Padding != Padding.Empty)
				{
					return this.CustomSettings.Padding;
				}

				return this.systemSettings.TaskPane.Padding;
			}
		}

		#endregion

		#region SystemSettings

		/// <summary>
		/// Gets or sets the system defined settings for the TaskPane
		/// </summary>
		protected internal ExplorerBarInfo SystemSettings
		{
			get
			{
				return this.systemSettings;
			}

			set
			{
				// ignore null values
				if (value == null)
				{
					return;
				}
				
				if (this.systemSettings != value)
				{
					this.SuspendLayout();
					
					if (this.systemSettings != null)
					{
						this.systemSettings.Dispose();
						this.systemSettings = null;
					}

					this.watermarkRect = Rectangle.Empty;

					this.systemSettings = value;
					this.BackColor = this.GradientStartColor;
					this.BackgroundImage = this.BackImage;

					foreach (Expando expando in this.Expandos)
					{
						expando.SystemSettings = this.systemSettings;
						expando.DoLayout();
					}

					this.DoLayout();

					this.ResumeLayout(true);

					this.Invalidate(true);
				}
			}
		}


		/// <summary>
		/// Gets the custom settings for the TaskPane
		/// </summary>
		[Category("Appearance"),
		Description(""),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		TypeConverter(typeof(TaskPaneInfoConverter))]
		public TaskPaneInfo CustomSettings
		{
			get
			{
				return this.customSettings;
			}

			set
			{
				this.customSettings = value;
			}
		}


		/// <summary>
		/// Resets the custom settings to their default values
		/// </summary>
		public void ResetCustomSettings()
		{
			this.CustomSettings.SetDefaultEmptyValues();

			this.FireCustomSettingsChanged(EventArgs.Empty);
		}

		#endregion

		#endregion


		#region Events

		#region Controls

		/// <summary>
		/// Raises the ControlAdded event
		/// </summary>
		/// <param name="e">A ControlEventArgs that contains the event data</param>
		protected override void OnControlAdded(ControlEventArgs e)
		{
			// make sure the control is an Expando
			if ((e.Control as Expando) == null)
			{
				// remove the control
				this.Controls.Remove(e.Control);

				// throw a hissy fit
				throw new InvalidCastException("Only Expando's can be added to the TaskPane");
			}
			
			base.OnControlAdded(e);

			// add the expando to the ExpandoCollection if necessary
			if (!this.Expandos.Contains((Expando) e.Control))
			{
				this.Expandos.Add((Expando) e.Control);
			}
		}


		/// <summary>
		/// Raises the ControlRemoved event
		/// </summary>
		/// <param name="e">A ControlEventArgs that contains the event data</param>
		protected override void OnControlRemoved(ControlEventArgs e)
		{
			base.OnControlRemoved (e);

			// remove the control from the itemList
			if (this.Expandos.Contains(e.Control))
			{
				this.Expandos.Remove((Expando) e.Control);
			}

			// update the layout of the controls
			this.DoLayout();
		}

		#endregion

		#region Custom Settings

		/// <summary>
		/// Raises the CustomSettingsChanged event
		/// </summary>
		/// <param name="e">An EventArgs that contains the event data</param>
		internal void FireCustomSettingsChanged(EventArgs e)
		{
			this.BackColor = this.GradientStartColor;
			this.BackgroundImage = this.BackImage;
				
			this.DoLayout();

			this.Invalidate(true);

			this.OnCustomSettingsChanged(e);
		}


		/// <summary>
		/// Raises the CustomSettingsChanged event
		/// </summary>
		/// <param name="e">An EventArgs that contains the event data</param>
		protected virtual void OnCustomSettingsChanged(EventArgs e)
		{
			if (CustomSettingsChanged != null)
			{
				CustomSettingsChanged(this, e);
			}
		}

		#endregion

		#region Expandos

		/// <summary> 
		/// Event handler for the Expando StateChanged event
		/// </summary>
		/// <param name="sender">The object that fired the event</param>
		/// <param name="e">An ExpandoEventArgs that contains the event data</param>
		private void expando_StateChanged(object sender, ExpandoEventArgs e)
		{
			this.OnExpandoStateChanged(e);
		}


		/// <summary>
		/// Occurs when the value of an Expandos Collapsed property changes
		/// </summary>
		/// <param name="e">An ExpandoEventArgs that contains the event data</param>
		protected virtual void OnExpandoStateChanged(ExpandoEventArgs e)
		{
			this.DoLayout(true);
		}


		/// <summary>
		/// Raises the ExpandoAdded event
		/// </summary>
		/// <param name="e">An ExpandoEventArgs that contains the event data</param>
		protected virtual void OnExpandoAdded(ExpandoEventArgs e)
		{
			// add the expando to the ControlCollection if it hasn't already
			if (!this.Controls.Contains(e.Expando))
			{
				this.Controls.Add(e.Expando);
			}

			// set anchor styles
			e.Expando.Anchor = (AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right);		
			
			// tell the Expando who's its daddy...
			e.Expando.TaskPane = this;
			e.Expando.SystemSettings = this.systemSettings;

			// listen for collapse/expand events
			e.Expando.StateChanged += new ExpandoEventHandler(this.expando_StateChanged);

			// update the layout of the controls
			this.DoLayout();

			//
			if (ExpandoAdded != null)
			{
				ExpandoAdded(this, e);
			}
		}


		/// <summary>
		/// Raises the ExpandoRemoved event
		/// </summary>
		/// <param name="e">An ExpandoEventArgs that contains the event data</param>
		protected virtual void OnExpandoRemoved(ExpandoEventArgs e)
		{
			// remove the control from the ControlCollection if it hasn't already
			if (this.Controls.Contains(e.Expando))
			{
				this.Controls.Remove(e.Expando);
			}

			// remove the StateChanged listener
			e.Expando.StateChanged -= new ExpandoEventHandler(this.expando_StateChanged);

			// update the layout of the controls
			this.DoLayout();

			//
			if (ExpandoRemoved != null)
			{
				ExpandoRemoved(this, e);
			}
		}

		#endregion

		#region Paint

		/// <summary> 
		/// Raises the PaintBackground event
		/// </summary>
		/// <param name="e">A PaintEventArgs that contains the event data</param>
		protected override void OnPaintBackground(PaintEventArgs e)
		{
			// paint background
			if (this.BackImage != null)
			{
				//base.OnPaintBackground(e);

				WrapMode wrap = WrapMode.Clamp;
				
				if ((this.StretchMode == ImageStretchMode.Tile) || (this.StretchMode == ImageStretchMode.Horizontal))
				{
					wrap = WrapMode.Tile;
				}

				using (TextureBrush brush = new TextureBrush(this.BackImage, wrap))
				{
					e.Graphics.FillRectangle(brush, this.DisplayRectangle);
				}
			}
			else
			{
				if (this.GradientStartColor != this.GradientEndColor)
				{
					using (LinearGradientBrush brush = new LinearGradientBrush(this.DisplayRectangle, 
							   this.GradientStartColor, 
							   this.GradientEndColor, 
							   this.GradientDirection))
					{
						e.Graphics.FillRectangle(brush, this.DisplayRectangle);
					}
				}
				else
				{
					using (SolidBrush brush = new SolidBrush(this.GradientStartColor))
					{
						e.Graphics.FillRectangle(brush, this.ClientRectangle);
					}
				}
			}

			// draw the watermark if we have one
			if (this.Watermark != null)
			{
				Rectangle rect = new Rectangle(0, 0, this.Watermark.Width, this.Watermark.Height);

				// work out a rough location of where the watermark should go

				switch (this.WatermarkAlignment)
				{
					case ContentAlignment.BottomCenter:
					case ContentAlignment.BottomLeft:
					case ContentAlignment.BottomRight:
					{
						rect.Y = this.DisplayRectangle.Bottom - this.Watermark.Height;
						
						break;
					}

					case ContentAlignment.MiddleCenter:
					case ContentAlignment.MiddleLeft:
					case ContentAlignment.MiddleRight:
					{
						rect.Y = this.DisplayRectangle.Top + ((this.DisplayRectangle.Height - this.Watermark.Height) / 2);
						
						break;
					}
				}

				switch (this.WatermarkAlignment)
				{
					case ContentAlignment.BottomRight:
					case ContentAlignment.MiddleRight:
					case ContentAlignment.TopRight:
					{
						rect.X = this.ClientRectangle.Right - this.Watermark.Width;
						
						break;
					}

					case ContentAlignment.BottomCenter:
					case ContentAlignment.MiddleCenter:
					case ContentAlignment.TopCenter:
					{
						rect.X = this.ClientRectangle.Left + ((this.ClientRectangle.Width - this.Watermark.Width) / 2);
						
						break;
					}
				}

				// shrink the destination rect if necesary so that we
				// can see all of the image
				
				if (rect.X < 0)
				{
					rect.X = 0;
				}

				if (rect.Width > this.ClientRectangle.Width)
				{
					rect.Width = this.ClientRectangle.Width;
				}

				if (rect.Y < this.DisplayRectangle.Top)
				{
					rect.Y = this.DisplayRectangle.Top;
				}

				if (rect.Height > this.DisplayRectangle.Height)
				{
					rect.Height = this.DisplayRectangle.Height;
				}

				// draw the watermark
				e.Graphics.DrawImage(this.Watermark, rect);
			}
		}

		#endregion

		#region Parents

		// fix: TaskPane will now perform a layout when its 
		//      parent becomes visible
		//      Brian Nottingham (nottinbe@slu.edu)
		//      22/12/2004
		//      v3.0
		
		/// <summary>
		/// Event handler for the ParentChanged event
		/// </summary>
		/// <param name="sender">The object that fired the event</param>
		/// <param name="e">An EventArgs that contains the event data</param>
		private void OnParentChanged(object sender, EventArgs e)
		{
			if (this.Parent != null)
			{
				this.Parent.VisibleChanged += new EventHandler(this.OnParentVisibleChanged);
			}
		}


		/// <summary>
		/// Event handler for the ParentVisibleChanged event
		/// </summary>
		/// <param name="sender">The object that fired the event</param>
		/// <param name="e">An EventArgs that contains the event data</param>
		private void OnParentVisibleChanged(object sender, EventArgs e)
		{
			if (sender != this.Parent)
			{
				((Control) sender).VisibleChanged -= new EventHandler(this.OnParentVisibleChanged);
				
				return;
			}

			if (this.Parent.Visible)
			{
				this.DoLayout();
			}
		}

		#endregion

		#region System Colors

		/// <summary> 
		/// Raises the SystemColorsChanged event
		/// </summary>
		/// <param name="e">An EventArgs that contains the event data</param>
		protected override void OnSystemColorsChanged(EventArgs e)
		{
			base.OnSystemColorsChanged(e);

			// don't go any further if we are explicitly using
			// the classic or a custom theme
			if (this.classicTheme || this.customTheme)
			{
				return;
			}

			this.SuspendLayout();

			// get rid of the current system theme info
			this.systemSettings.Dispose();
			this.systemSettings = null;

			// get a new system theme info for the new theme
			this.systemSettings = ThemeManager.GetSystemExplorerBarSettings();
			
			this.BackgroundImage = this.BackImage;


			// update the system settings for each expando
			foreach (Control control in this.Controls)
			{
				if (control is Expando)
				{
					Expando expando = (Expando) control;
					
					expando.SystemSettings = this.systemSettings;
				}
			}

			// update the layout of the controls
			this.DoLayout();

			this.ResumeLayout(true);
		}

		#endregion

		#endregion


		#region ExpandoCollection

		/// <summary>
		/// Represents a collection of Expando objects
		/// </summary>
		public class ExpandoCollection : CollectionBase
		{
			#region Class Data

			/// <summary>
			/// The TaskPane that owns this ExpandoCollection
			/// </summary>
			private TaskPane owner;

			#endregion


			#region Constructor

			/// <summary>
			/// Initializes a new instance of the TaskPane.ExpandoCollection class
			/// </summary>
			/// <param name="owner">A TaskPane representing the taskpane that owns 
			/// the Expando collection</param>
			public ExpandoCollection(TaskPane owner) : base()
			{
				if (owner == null)
				{
					throw new ArgumentNullException("owner");
				}
				
				this.owner = owner;
			}

			#endregion


			#region Methods

			/// <summary>
			/// Adds the specified expando to the expando collection
			/// </summary>
			/// <param name="value">The Expando to add to the expando collection</param>
			public void Add(Expando value)
			{
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}

				this.List.Add(value);
				this.owner.Controls.Add(value);

				this.owner.OnExpandoAdded(new ExpandoEventArgs(value));
			}


			/// <summary>
			/// Adds an array of expando objects to the collection
			/// </summary>
			/// <param name="expandos">An array of Expando objects to add 
			/// to the collection</param>
			public void AddRange(Expando[] expandos)
			{
				if (expandos == null)
				{
					throw new ArgumentNullException("expandos");
				}

				for (int i=0; i<expandos.Length; i++)
				{
					this.Add(expandos[i]);
				}
			}
			
			
			/// <summary>
			/// Removes all expandos from the collection
			/// </summary>
			public new void Clear()
			{
				while (this.Count > 0)
				{
					this.RemoveAt(0);
				}
			}


			/// <summary>
			/// Determines whether the specified expando is a member of the 
			/// collection
			/// </summary>
			/// <param name="expando">The Expando to locate in the collection</param>
			/// <returns>true if the Expando is a member of the collection; 
			/// otherwise, false</returns>
			public bool Contains(Expando expando)
			{
				if (expando == null)
				{
					throw new ArgumentNullException("expando");
				}

				return (this.IndexOf(expando) != -1);
			}


			/// <summary>
			/// Determines whether the specified control is a member of the 
			/// collection
			/// </summary>
			/// <param name="control">The Control to locate in the collection</param>
			/// <returns>true if the Control is a member of the collection; 
			/// otherwise, false</returns>
			public bool Contains(Control control)
			{
				if (!(control is Expando))
				{
					return false;
				}

				return this.Contains((Expando) control);
			}


			/// <summary>
			/// Retrieves the index of the specified expando in the expando 
			/// collection
			/// </summary>
			/// <param name="expando">The Expando to locate in the collection</param>
			/// <returns>A zero-based index value that represents the position 
			/// of the specified Expando in the TaskPane.ExpandoCollection</returns>
			public int IndexOf(Expando expando)
			{
				if (expando == null)
				{
					throw new ArgumentNullException("expando");
				}
				
				for (int i=0; i<this.Count; i++)
				{
					if (this[i] == expando)
					{
						return i;
					}
				}

				return -1;
			}


			/// <summary>
			/// Removes the specified expando from the expando collection
			/// </summary>
			/// <param name="value">The Expando to remove from the 
			/// TaskPane.ExpandoCollection</param>
			public void Remove(Expando value)
			{
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}

				this.List.Remove(value);

				this.owner.Controls.Remove(value);

				this.owner.OnExpandoRemoved(new ExpandoEventArgs(value));
			}

			
			/// <summary>
			/// Removes an expando from the expando collection at the 
			/// specified indexed location
			/// </summary>
			/// <param name="index">The index value of the Expando to 
			/// remove</param>
			public new void RemoveAt(int index)
			{
				this.Remove(this[index]);
			}


			/// <summary>
			/// Moves the specified expando to the specified indexed location 
			/// in the expando collection
			/// </summary>
			/// <param name="value">The expando to be moved</param>
			/// <param name="index">The indexed location in the expando collection 
			/// that the specified expando will be moved to</param>
			public void Move(Expando value, int index)
			{
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}

				// make sure the index is within range
				if (index < 0)
				{
					index = 0;
				}
				else if (index > this.Count)
				{
					index = this.Count;
				}

				// don't go any further if the expando is already 
				// in the desired position or we don't contain it
				if (!this.Contains(value) || this.IndexOf(value) == index)
				{
					return;
				}

				this.List.Remove(value);

				// if the index we're supposed to move the expando to
				// is now greater to the number of expandos contained, 
				// add it to the end of the list, otherwise insert it at 
				// the specified index
				if (index > this.Count)
				{
					this.List.Add(value);
				}
				else
				{
					this.List.Insert(index, value);
				}

				// re-layout the controls
				this.owner.MatchControlCollToExpandoColl();
			}


			/// <summary>
			/// Moves the specified expando to the top of the expando collection
			/// </summary>
			/// <param name="value">The expando to be moved</param>
			public void MoveToTop(Expando value)
			{
				this.Move(value, 0);
			}


			/// <summary>
			/// Moves the specified expando to the bottom of the expando collection
			/// </summary>
			/// <param name="value">The expando to be moved</param>
			public void MoveToBottom(Expando value)
			{
				this.Move(value, this.Count);
			}

			#endregion


			#region Properties

			/// <summary>
			/// The Expando located at the specified index location within 
			/// the expando collection
			/// </summary>
			/// <param name="index">The index of the expando to retrieve 
			/// from the expando collection</param>
			public virtual Expando this[int index]
			{
				get
				{
					return this.List[index] as Expando;
				}
			}

			#endregion
		}

		#endregion
	
	
		#region ExpandoCollectionEditor

		/// <summary>
		/// A custom CollectionEditor for editing ExpandoCollections
		/// </summary>
		internal class ExpandoCollectionEditor : CollectionEditor
		{
			/// <summary>
			/// Initializes a new instance of the CollectionEditor class 
			/// using the specified collection type
			/// </summary>
			/// <param name="type"></param>
			public ExpandoCollectionEditor(Type type) : base(type)
			{
			
			}


			/// <summary>
			/// Edits the value of the specified object using the specified 
			/// service provider and context
			/// </summary>
			/// <param name="context">An ITypeDescriptorContext that can be 
			/// used to gain additional context information</param>
			/// <param name="isp">A service provider object through which 
			/// editing services can be obtained</param>
			/// <param name="value">The object to edit the value of</param>
			/// <returns>The new value of the object. If the value of the 
			/// object has not changed, this should return the same object 
			/// it was passed</returns>
			public override object EditValue(ITypeDescriptorContext context, IServiceProvider isp, object value)
			{
				TaskPane originalControl = (TaskPane) context.Instance;

				object returnObject = base.EditValue(context, isp, value);

				originalControl.UpdateExpandos();

				return returnObject;
			}


			/// <summary>
			/// Creates a new instance of the specified collection item type
			/// </summary>
			/// <param name="itemType">The type of item to create</param>
			/// <returns>A new instance of the specified object</returns>
			protected override object CreateInstance(Type itemType)
			{
				object expando = base.CreateInstance(itemType);
			
				((Expando) expando).Name = "expando";
			
				return expando;
			}
		}

		#endregion


		#region TaskPaneSurrogate

		/// <summary>
		/// A class that is serialized instead of a TaskPane (as 
		/// TaskPanes contain objects that cause serialization problems)
		/// </summary>
		[Serializable(),
		XmlRoot("TaskPaneSurrogate", Namespace="", IsNullable=false)]
		public class TaskPaneSurrogate : ISerializable
		{
			#region Class Data

			/// <summary>
			/// See TaskPane.Name.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public string Name;

			/// <summary>
			/// See TaskPane.Size.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public Size Size;
			
			/// <summary>
			/// See TaskPane.Location.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public Point Location;
			
			/// <summary>
			/// See TaskPane.BackColor.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public string BackColor;
			
			/// <summary>
			/// See TaskPane.CustomSettings.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public TaskPaneInfo.TaskPaneInfoSurrogate CustomSettings;
			
			/// <summary>
			/// See TaskPane.AutoScroll.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public bool AutoScroll;
			
			/// <summary>
			/// See TaskPane.AutoScrollMargin.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public Size AutoScrollMargin;
			
			/// <summary>
			/// See TaskPane.Enabled.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public bool Enabled;
			
			/// <summary>
			/// See TaskPane.Visible.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public bool Visible;
			
			/// <summary>
			/// See TaskPane.Anchor.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public AnchorStyles Anchor;
			
			/// <summary>
			/// See TaskPane.Dock.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public DockStyle Dock;
			
			/// <summary>
			/// See Font.Name.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public string FontName;
			
			/// <summary>
			/// See Font.Size.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public float FontSize;
			
			/// <summary>
			/// See Font.Style.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			public FontStyle FontDecoration;

			/// <summary>
			/// See TaskPane.Expandos.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			[XmlArray("Expandos"), XmlArrayItem("ExpandoSurrogate", typeof(Expando.ExpandoSurrogate))]
			public ArrayList Expandos;

			/// <summary>
			/// See Control.Tag.  This member is not intended to be used 
			/// directly from your code.
			/// </summary>
			[XmlElementAttribute("Tag", typeof(Byte[]), DataType="base64Binary")]
			public byte[] Tag;

			/// <summary>
			/// Version number of the surrogate.  This member is not intended 
			/// to be used directly from your code.
			/// </summary>
			public int Version = 3211;

			#endregion


			#region Constructor

			/// <summary>
			/// Initializes a new instance of the TaskPaneSurrogate class with default settings
			/// </summary>
			public TaskPaneSurrogate()
			{
				this.Name = null;

				this.Size = Size.Empty;
				this.Location = Point.Empty;

				this.BackColor = ThemeManager.ConvertColorToString(SystemColors.Control);

				this.CustomSettings = null;

				this.AutoScroll = false;
				this.AutoScrollMargin = Size.Empty;

				this.Enabled = true;
				this.Visible = true;

				this.Anchor = AnchorStyles.None;
				this.Dock = DockStyle.None;

				this.FontName = "Tahoma";
				this.FontSize = 8.25f;
				this.FontDecoration = FontStyle.Regular;

				this.Tag = new byte[0];

				this.Expandos = new ArrayList();
			}

			#endregion


			#region Methods

			/// <summary>
			/// Populates the TaskPaneSurrogate with data that is to be 
			/// serialized from the specified TaskPane
			/// </summary>
			/// <param name="taskPane">The TaskPane that contains the data 
			/// to be serialized</param>
			public void Load(TaskPane taskPane)
			{
				this.Name = taskPane.Name;
				this.Size = taskPane.Size;
				this.Location = taskPane.Location;

				this.BackColor = ThemeManager.ConvertColorToString(taskPane.BackColor);

				this.CustomSettings = new TaskPaneInfo.TaskPaneInfoSurrogate();
				this.CustomSettings.Load(taskPane.CustomSettings);

				this.AutoScroll = taskPane.AutoScroll;
				this.AutoScrollMargin = taskPane.AutoScrollMargin;

				this.Enabled = taskPane.Enabled;
				this.Visible = taskPane.Visible;

				this.Anchor = taskPane.Anchor;
				this.Dock = taskPane.Dock;

				this.FontName = taskPane.Font.FontFamily.Name;
				this.FontSize = taskPane.Font.SizeInPoints;
				this.FontDecoration = taskPane.Font.Style;

				this.Tag = ThemeManager.ConvertObjectToByteArray(taskPane.Tag);

				foreach (Expando expando in taskPane.Expandos)
				{
					Expando.ExpandoSurrogate es = new Expando.ExpandoSurrogate();

					es.Load(expando);

					this.Expandos.Add(es);
				}
			}


			/// <summary>
			/// Returns a TaskPane that contains the deserialized TaskPaneSurrogate data
			/// </summary>
			/// <returns>A TaskPane that contains the deserialized TaskPaneSurrogate data</returns>
			public TaskPane Save()
			{
				TaskPane taskPane = new TaskPane();
				((ISupportInitialize) taskPane).BeginInit();
				taskPane.SuspendLayout();

				taskPane.Name = this.Name;
				taskPane.Size = this.Size;
				taskPane.Location = this.Location;

				taskPane.BackColor = ThemeManager.ConvertStringToColor(this.BackColor);

				taskPane.customSettings = this.CustomSettings.Save();
				taskPane.customSettings.TaskPane = taskPane;

				taskPane.AutoScroll = this.AutoScroll;
				taskPane.AutoScrollMargin = this.AutoScrollMargin;

				taskPane.Enabled = this.Enabled;
				taskPane.Visible = this.Visible;

				taskPane.Anchor = this.Anchor;
				taskPane.Dock = this.Dock;

				taskPane.Font = new Font(this.FontName, this.FontSize, this.FontDecoration);

				taskPane.Tag = ThemeManager.ConvertByteArrayToObject(this.Tag);

				foreach (Object o in this.Expandos)
				{
					Expando e = ((Expando.ExpandoSurrogate) o).Save();
					
					taskPane.Expandos.Add(e);
				}

				((ISupportInitialize) taskPane).EndInit();
				taskPane.ResumeLayout(false);

				return taskPane;
			}

			
			/// <summary>
			/// Populates a SerializationInfo with the data needed to serialize the TaskPaneSurrogate
			/// </summary>
			/// <param name="info">The SerializationInfo to populate with data</param>
			/// <param name="context">The destination for this serialization</param>
			[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
			public void GetObjectData(SerializationInfo info, StreamingContext context)
			{
				info.AddValue("Version", this.Version);
				
				info.AddValue("Name", this.Name);
				info.AddValue("Size", this.Size);
				info.AddValue("Location", this.Location);

				info.AddValue("BackColor", this.BackColor);

				info.AddValue("CustomSettings", this.CustomSettings);

				info.AddValue("AutoScroll", this.AutoScroll);
				info.AddValue("AutoScrollMargin", this.AutoScrollMargin);

				info.AddValue("Enabled", this.Enabled);
				info.AddValue("Visible", this.Visible);

				info.AddValue("Anchor", this.Anchor);
				info.AddValue("Dock", this.Dock);
				
				info.AddValue("FontName", this.FontName);
				info.AddValue("FontSize", this.FontSize);
				info.AddValue("FontDecoration", this.FontDecoration);
				
				info.AddValue("Tag", this.Tag);
				
				info.AddValue("Expandos", this.Expandos);
			}


			/// <summary>
			/// Initializes a new instance of the TaskPaneSurrogate class using the information 
			/// in the SerializationInfo
			/// </summary>
			/// <param name="info">The information to populate the TaskPaneSurrogate</param>
			/// <param name="context">The source from which the TaskPaneSurrogate is deserialized</param>
			[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
			protected TaskPaneSurrogate(SerializationInfo info, StreamingContext context) : base()
			{
				int version = info.GetInt32("Version");

				this.Name = info.GetString("Name");
				this.Size = (Size) info.GetValue("Size", typeof(Size));
				this.Location = (Point) info.GetValue("Location", typeof(Point));

				this.BackColor = info.GetString("BackColor");

				this.CustomSettings = (TaskPaneInfo.TaskPaneInfoSurrogate) info.GetValue("CustomSettings", typeof(TaskPaneInfo.TaskPaneInfoSurrogate));

				this.AutoScroll = info.GetBoolean("AutoScroll");
				this.AutoScrollMargin = (Size) info.GetValue("AutoScrollMargin", typeof(Size));

				this.Enabled = info.GetBoolean("Enabled");
				this.Visible = info.GetBoolean("Visible");
				
				this.Anchor = (AnchorStyles) info.GetValue("Anchor", typeof(AnchorStyles));
				this.Dock = (DockStyle) info.GetValue("Dock", typeof(DockStyle));

				this.FontName = info.GetString("FontName");
				this.FontSize = info.GetSingle("FontSize");
				this.FontDecoration = (FontStyle) info.GetValue("FontDecoration", typeof(FontStyle));

				this.Tag = (byte[]) info.GetValue("Tag", typeof(byte[]));

				this.Expandos = (ArrayList) info.GetValue("Expandos", typeof(ArrayList));
			}

			#endregion
		}

		#endregion
	}

	#endregion



	#region TaskPaneDesigner

	/// <summary>
	/// A custom designer used by TaskPanes to remove unwanted 
	/// properties from the Property window in the designer
	/// </summary>
	internal class TaskPaneDesigner : ScrollableControlDesigner
	{
		/// <summary>
		/// Initializes a new instance of the TaskPaneDesigner class
		/// </summary>
		public TaskPaneDesigner() : base()
		{
			
		}


		/// <summary>
		/// Adjusts the set of properties the component exposes through 
		/// a TypeDescriptor
		/// </summary>
		/// <param name="properties">An IDictionary containing the properties 
		/// for the class of the component</param>
		protected override void PreFilterProperties(System.Collections.IDictionary properties)
		{
			base.PreFilterProperties(properties);

			properties.Remove("BackColor");
			properties.Remove("BackgroundImage");
			properties.Remove("Cursor");
			properties.Remove("ForeColor");
		}
	}

	#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
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions