Click here to Skip to main content
15,892,161 members
Articles / Programming Languages / C#

IconPanel Custom Control

Rate me:
Please Sign up or sign in to vote.
4.86/5 (13 votes)
21 Sep 20048 min read 85.2K   3.7K   77  
An expanding/collapsing 'Task Tray' ala Windows XP and Longhorn
using System;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Design;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;

namespace UIComponents.Designers {
	/// <summary>
	/// ImageMapEditor provides a drop-down pop-up of all images in the
	/// associated <see cref="ImageSet"/>
	/// </summary>
	public class ImageMapEditor	: UITypeEditor {
		#region Fields
		/// <summary>
		/// Service used to provide the image popup
		/// </summary>
		private IWindowsFormsEditorService wfes = null ;

		/// <summary>
		/// Image selected from the popup (-1 is cancel)
		/// </summary>
		private int selectedIndex = -1 ;

		/// <summary>
		/// Instance of <see cref="ImagePanel"/> for the drop-down pop-up
		/// </summary>
		private ImagePanel imagePanel = null ;
		#endregion Fields

		/// <summary>
		/// Create an <c>ImageMapEditor</c>
		/// </summary>
		public ImageMapEditor() {}

		/// <summary>
		/// Tell the designer we use the <see cref="UITypeEditorEditStyle.DropDown"/>
		/// style
		/// </summary>
		/// <param name="context">designer context</param>
		/// <returns>
		/// <see cref="UITypeEditorEditStyle.DropDown"/> if the context and instance
		/// are valid, otherwise whatever the base class says
		/// </returns>
		public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) {
			if(context != null && context.Instance != null ) {
				return UITypeEditorEditStyle.DropDown ;
			}
			return base.GetEditStyle(context) ;
		}

		/// <summary>
		/// Extract the <see cref="ImageSet"/> associated with the instance
		/// being edited
		/// </summary>
		/// <param name="component">The item being edited</param>
		/// <returns>
		/// The edited items associated <see cref="ImageSet"/> or 
		/// <see langword="null"/> if it cant be found or is 
		/// undefined
		/// </returns>
		protected virtual ImageSet GetImageSet(object component) {
			if (component is ImageItemCollection) {
				return ((ImageItemCollection) component).ImageSet ;
			}

			return null ;
		}

		/// <summary>
		/// Yes we paint values
		/// </summary>
		/// <param name="context">designer context</param>
		/// <returns>
		/// <see langword="true"/>
		/// </returns>
		public override bool GetPaintValueSupported(ITypeDescriptorContext context) {
			return true;
		}

		/// <summary>
		/// Paint a preview of the <see cref="Image"/> specified by
		/// the image index provided by the <see cref="PaintValueEventArgs"/>
		/// </summary>
		/// <param name="pe">The PaintValue event args</param>
		public override void PaintValue(PaintValueEventArgs pe) {
			int imageIndex = -1 ;	

			// value is the image index
			if(pe.Value != null) {
				try {
					imageIndex = (int)Convert.ToUInt16( pe.Value.ToString() ) ;
				}
				catch {}
			}

			// no instance, or the instance represents an undefined image
			if((pe.Context.Instance == null) || (imageIndex < 0))
				return ;

			// get the image set
			ImageSet imageSet = GetImageSet(pe.Context.Instance) ;

			// make sure everything is valid
			if((imageSet == null) || (imageSet.Count == 0) || (imageIndex >= imageSet.Count))
				return ;

			// Draw the preview image
			pe.Graphics.DrawImage(imageSet.Images[imageIndex],pe.Bounds);
		}

		/// <summary>
		/// When editing an image index value, let the user choose an image from
		/// a popup that displays all the images in the associated <see cref="ImageSet"/>
		/// </summary>
		/// <param name="context">designer context</param>
		/// <param name="provider">designer service provider</param>
		/// <param name="value">image index item</param>
		/// <returns>
		/// An image index (selected from the popup) or -1 if the user canceled the
		/// selection
		/// </returns>
		public override object EditValue(ITypeDescriptorContext context,IServiceProvider provider,object value) {
			wfes = (IWindowsFormsEditorService)
				provider.GetService(typeof(IWindowsFormsEditorService));

			if((wfes == null) || (context == null))
				return null ;

			// Get the image set
			ImageSet imageSet = GetImageSet(context.Instance) ;

			// anything to show?
			if ((imageSet == null) || (imageSet.Count==0))
				return -1 ;

			// Create an image panel that is close to square
			Size dims = ImagePanel.CalculateBestDimensions(imageSet.Count,ImagePanel.PanelSizeHints.MinimizeBoth) ;
			imagePanel = new ImagePanel((Bitmap) imageSet.Preview,imageSet.Count,dims.Height,dims.Width) ;
			// set the current image index value as the default selection
			imagePanel.DefaultImage = (int) value ;
			// no grid
			imagePanel.GridColor = Color.Empty ;
			// listen for an image to be selected
			imagePanel.ImageSelected += new EventHandler(imagePanel_ImageSelected);

			// show the popup as a drop-down
			wfes.DropDownControl(imagePanel) ;
			
			// return the selection (or the original value if none selected)
			return (selectedIndex != -1) ? selectedIndex : (int) value ;
		}

		/// <summary>
		/// <see cref="ImagePanel.ImageSelected"/> listener
		/// </summary>
		/// <param name="sender">The <see cref="ImagePanel"/></param>
		/// <param name="e"><see cref="ImageSelectedEventArgs"/> specifying the selection (or -1)</param>
		private void imagePanel_ImageSelected(object sender, EventArgs e) {
			// get the selection
			selectedIndex = ((ImageSelectedEventArgs) e).ImageIndex ;
			// remove the listener
			imagePanel.ImageSelected -= new EventHandler(imagePanel_ImageSelected);
			// close the drop-dwon, we are done
			wfes.CloseDropDown() ;

			imagePanel.Dispose() ;
			imagePanel = null ;
		}
	}
}

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
United States United States
I have been bumming around doing Software development for 22+ years. A bit of everything, including a most enjoyable stint at NuMega Technologies where I (and 2-3 other amazing developers) wrote SoftICE/95, SoftICE for Windows NT 3.0 and 3.5. I also developed the MACH5 technology behind the TrueTime profiler. During my time there I was fortunate enough to have the office next to Matt Pietrek and saw 1st hand the demands and difficulties of writing about software and software development. Still, I spent 2 years as a monthly columnist writing about Java technologies.

As of this time, I just write a lot of code, mostly C#, but some C++/ATL/COM, Assembler, and the occasional VB6/VB.NET. I focus mainly on UI because I spent so much time in the bowels of the OS that it just plain bores me.

Comments and Discussions