Click here to Skip to main content
15,881,172 members
Articles / Programming Languages / XML

Enhanced BrowseForFolder Styled TreeView

Rate me:
Please Sign up or sign in to vote.
4.86/5 (85 votes)
27 May 2013Apache5 min read 576.9K   16.8K   269  
Supports Explorer, SingleChecked and RecursiveChecked mode (checkboxes). Lets you specify the displayed drive types, etc...
using System;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.ComponentModel;
using System.Drawing;

namespace Raccoom.Windows.Forms.Design
{
	/// <summary>
	/// Implements a custom type editor for enum's with FlagAttribute
	/// </summary>
	/// <remarks>
	/// Copyright by Thierry Bouquain, <a href="http://www.codeproject.com/cs/miscctrl/flagseditor.asp?target=FlagsEditor" target="_blank">A flag editor article on codeproject.com</a>
	/// </remarks>
	public class FlagsEditor : UITypeEditor
	{
		/// <summary>
		/// Internal class used for storing custom data in listviewitems
		/// </summary>
		internal class clbItem
		{
			/// <summary>
			/// Creates a new instance of the <c>clbItem</c>
			/// </summary>
			/// <param name="str">The string to display in the <c>ToString</c> method. 
			/// It will contains the name of the flag</param>
			/// <param name="value">The integer value of the flag</param>
			/// <param name="tooltip">The tooltip to display in the <see cref="CheckedListBox"/></param>
			public clbItem(string str, int value, string tooltip)
			{
				this.str = str;
				this.value = value;
				this.tooltip = tooltip;
			}

			private string str;

			private int value;
			/// <summary>
			/// Gets the int value for this item
			/// </summary>
			public int Value
			{
				get{return value;}
			}

			private string tooltip;

			/// <summary>
			/// Gets the tooltip for this item
			/// </summary>
			public string Tooltip
			{
				get{return tooltip;}
			}

			/// <summary>
			/// Gets the name of this item
			/// </summary>
			/// <returns>The name passed in the constructor</returns>
			public override string ToString()
			{
				return str;
			}
		}

		private IWindowsFormsEditorService edSvc = null;
		private CheckedListBox clb;
		private ToolTip tooltipControl;

		/// <summary>
		/// Overrides the method used to provide basic behaviour for selecting editor.
		/// Shows our custom control for editing the value.
		/// </summary>
		/// <param name="context">The context of the editing control</param>
		/// <param name="provider">A valid service provider</param>
		/// <param name="value">The current value of the object to edit</param>
		/// <returns>The new value of the object</returns>
		public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) 
		{
			if (context != null
				&& context.Instance != null
				&& provider != null) 
			{

				edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

				if (edSvc != null) 
				{					
					// Create a CheckedListBox and populate it with all the enum values
					clb = new CheckedListBox();
					clb.BorderStyle = BorderStyle.FixedSingle;
					clb.CheckOnClick = true;
					clb.MouseDown += new MouseEventHandler(this.OnMouseDown);
					clb.MouseMove += new MouseEventHandler(this.OnMouseMoved);

					tooltipControl = new ToolTip();
					tooltipControl.ShowAlways = true;

					foreach(string name in Enum.GetNames(context.PropertyDescriptor.PropertyType))
					{
						// Get the enum value
						object enumVal = Enum.Parse(context.PropertyDescriptor.PropertyType, name);
						// Get the int value 
						int intVal = (int) Convert.ChangeType(enumVal, typeof(int));
						
						// Get the description attribute for this field
						System.Reflection.FieldInfo fi = context.PropertyDescriptor.PropertyType.GetField(name);
						DescriptionAttribute[] attrs = (DescriptionAttribute[]) fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

						// Store the the description
						string tooltip = attrs.Length > 0 ? attrs[0].Description : string.Empty;

						// Get the int value of the current enum value (the one being edited)
						int intEdited = (int) Convert.ChangeType(value, typeof(int));

						// Creates a clbItem that stores the name, the int value and the tooltip
						clbItem item = new clbItem(enumVal.ToString(), intVal, tooltip);

						// Get the checkstate from the value being edited
						//bool checkedItem = (intEdited & intVal) > 0;
						bool checkedItem = (intEdited & intVal) == intVal;

						// Add the item with the right check state
						clb.Items.Add(item, checkedItem);
					}					

					// Show our CheckedListbox as a DropDownControl. 
					// This methods returns only when the dropdowncontrol is closed
					edSvc.DropDownControl(clb);

					// Get the sum of all checked flags
					int result = 0;
					foreach(clbItem obj in clb.CheckedItems)
					{
						//result += obj.Value;
						result |= obj.Value;
					}
					
					// return the right enum value corresponding to the result
					return Enum.ToObject(context.PropertyDescriptor.PropertyType, result);
				}
			}

			return value;
		}

		/// <summary>
		/// Shows a dropdown icon in the property editor
		/// </summary>
		/// <param name="context">The context of the editing control</param>
		/// <returns>Returns <c>UITypeEditorEditStyle.DropDown</c></returns>
		public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) 
		{
			return UITypeEditorEditStyle.DropDown;			
		}

		private bool handleLostfocus = false;

		/// <summary>
		/// When got the focus, handle the lost focus event.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void OnMouseDown(object sender, MouseEventArgs e) 
		{
			if(!handleLostfocus && clb.ClientRectangle.Contains(clb.PointToClient(new Point(e.X, e.Y))))
			{
				clb.LostFocus += new EventHandler(this.ValueChanged);
				handleLostfocus = true;
			}
		}

		/// <summary>
		/// Occurs when the mouse is moved over the checkedlistbox. 
		/// Sets the tooltip of the item under the pointer
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void OnMouseMoved(object sender, MouseEventArgs e) 
		{			
			int index = clb.IndexFromPoint(e.X, e.Y);
			if(index >= 0)
				tooltipControl.SetToolTip(clb, ((clbItem) clb.Items[index]).Tooltip);
		}

		/// <summary>
		/// Close the dropdowncontrol when the user has selected a value
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ValueChanged(object sender, EventArgs e) 
		{
			if (edSvc != null) 
			{
				edSvc.CloseDropDown();
			}
		}
	}
}

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, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
Software Developer (Senior)
Switzerland Switzerland
My interest is in the future because I am going to spend the rest of my life there. (Charles Kettering)

Biography

  • 1996 - 1998 PC Board PPL, HTML, DHTML, Javascript and ASP
  • 1999 - 2001 coding Centura against Sql Database (SqlBase,MSSQL,Oracle)
  • 2002 - 2004 C# Windows Forms
  • 2005 - 2006 C# ASP.NET, Windows Forms
  • 2006 - 2009 C#, WCF, WF, WPF
  • 2010 - 2012 C#, Dynamics CRM, Sharepoint, Silverlight
  • 2013 - 2013 C#, WCF DS (OData), WF, WPF
  • 2014 - 2016 C#, Azure PaaS, Identity, OWIN, OData, Web Api
  • 2017 - now C#, aspnet.core, IdentityServer4, TypeScript & Angular @ Azure IaaS or PaaS

Interests

  • family & friends
  • chilaxing ,)
  • coding

Comments and Discussions