Click here to Skip to main content
15,896,118 members
Articles / Programming Languages / C#

Extending the PropertyGrid with a new PropertyTab

Rate me:
Please Sign up or sign in to vote.
4.89/5 (39 votes)
15 Jan 2007CPOL8 min read 121.3K   4.1K   128  
Add a PropertyTab showing the fields of an object and overlay icons to the PropertyGrid
namespace PropertyGridEx
{
    using Microsoft.VisualBasic;
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Drawing.Design;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Data;
    using System.Xml.Serialization;

    [Serializable(), XmlRootAttribute("CustomProperty")]
    public class CustomProperty
    {				
		#region "Private variables"
		
		// Common properties
		protected string sName = "";
		protected object oValue = null;
		protected bool bIsReadOnly = false;
		protected bool bVisible = true;
		protected string sDescription = "";
		protected string sCategory = "";
		protected bool bIsPassword = false;
		protected bool bIsPercentage = false;
		protected bool bParenthesize = false;
		
		// Filename editor properties
		protected string sFilter = null;
		protected UIFilenameEditor.FileDialogType eDialogType = UIFilenameEditor.FileDialogType.LoadFileDialog;
		protected bool bUseFileNameEditor = false;
		
		// Custom choices properties
		protected CustomChoices oChoices = null;
		
		// Browsable properties
		protected bool bIsBrowsable = false;
		protected BrowsableTypeConverter.LabelStyle eBrowsablePropertyLabel = BrowsableTypeConverter.LabelStyle.lsEllipsis;
		
		// Dynamic properties
		protected bool bRef = false;
		protected object oRef = null;
		protected string sProp = "";
		
		// Databinding properties
		protected object oDatasource = null;
		protected string sDisplayMember = null;
		protected string sValueMember = null;
		protected object oSelectedValue = null;
		protected object oSelectedItem = null;
		protected bool bIsDropdownResizable = false;
		
		// 3-dots button event handler
		protected UICustomEventEditor.OnClick MethodDelegate;
		
		// Extended Attributes
		[NonSerialized()]protected AttributeCollection oCustomAttributes = null;
		protected object oTag = null;
		protected object oDefaultValue = null;
		protected Type oDefaultType = null;
		
		// Custom Editor and Custom Type Converter
		[NonSerialized()]protected UITypeEditor oCustomEditor = null;
		[NonSerialized()]protected TypeConverter oCustomTypeConverter = null;
		
		#endregion
		
		#region "Public methods"
		
		public CustomProperty()
		{
			sName = "New Property";
			oValue = new string(' ',0);
		}
		
		public CustomProperty(string strName, object objValue, bool boolIsReadOnly, string strCategory, string strDescription, bool boolVisible)
		{
			sName = strName;
			oValue = objValue;
			bIsReadOnly = boolIsReadOnly;
			sDescription = strDescription;
			sCategory = strCategory;
			bVisible = boolVisible;
			if (oValue != null)
			{
				oDefaultValue = oValue;
			}
		}
		
		public CustomProperty(string strName, ref object objRef, string strProp, bool boolIsReadOnly, string strCategory, string strDescription, bool boolVisible)
		{
			sName = strName;
			bIsReadOnly = boolIsReadOnly;
			sDescription = strDescription;
			sCategory = strCategory;
			bVisible = boolVisible;
			bRef = true;
			oRef = objRef;
			sProp = strProp;
			if (Value != null)
			{
				oDefaultValue = Value;
			}
		}

        public void RebuildAttributes()
        {
            if (bUseFileNameEditor)
            {
                BuildAttributes_FilenameEditor();
            }
            else if (oChoices != null)
            {
                BuildAttributes_CustomChoices();
            }
            else if (oDatasource != null)
            {
                BuildAttributes_ListboxEditor();
            }
            else if (bIsBrowsable)
            {
                BuildAttributes_BrowsableProperty();
            }
        }
		
		#endregion
		
		#region "Private methods"
		
		private void BuildAttributes_FilenameEditor()
		{
			ArrayList attrs = new ArrayList();
			UIFilenameEditor.FileDialogFilterAttribute FilterAttribute = new UIFilenameEditor.FileDialogFilterAttribute(sFilter);
			UIFilenameEditor.SaveFileAttribute SaveDialogAttribute = new UIFilenameEditor.SaveFileAttribute();
			Attribute[] attrArray;
			attrs.Add(FilterAttribute);
			if (eDialogType == UIFilenameEditor.FileDialogType.SaveFileDialog)
			{
				attrs.Add(SaveDialogAttribute);
			}
			attrArray =  (System.Attribute[]) attrs.ToArray(typeof(Attribute));
			oCustomAttributes = new AttributeCollection(attrArray);
		}
		
		private void BuildAttributes_CustomChoices()
		{
			if (oChoices != null)
			{
				CustomChoices.CustomChoicesAttributeList list = new CustomChoices.CustomChoicesAttributeList(oChoices.Items);
				ArrayList attrs = new ArrayList();
				Attribute[] attrArray;
				attrs.Add(list);
				attrArray =  (System.Attribute[]) attrs.ToArray(typeof(Attribute));
				oCustomAttributes = new AttributeCollection(attrArray);
			}
		}
		
		private void BuildAttributes_ListboxEditor()
		{
			if (oDatasource != null)
			{
				UIListboxEditor.UIListboxDatasource ds = new UIListboxEditor.UIListboxDatasource(ref oDatasource);
				UIListboxEditor.UIListboxValueMember vm = new UIListboxEditor.UIListboxValueMember(sValueMember);
				UIListboxEditor.UIListboxDisplayMember dm = new UIListboxEditor.UIListboxDisplayMember(sDisplayMember);
				UIListboxEditor.UIListboxIsDropDownResizable ddr = null;
				ArrayList attrs = new ArrayList();
				attrs.Add(ds);
				attrs.Add(vm);
				attrs.Add(dm);
				if (bIsDropdownResizable)
				{
					ddr = new UIListboxEditor.UIListboxIsDropDownResizable();
					attrs.Add(ddr);
				}
				Attribute[] attrArray;
				attrArray =  (System.Attribute[]) attrs.ToArray(typeof(Attribute));
				oCustomAttributes = new AttributeCollection(attrArray);
			}
		}

        private void BuildAttributes_BrowsableProperty()
        {
            BrowsableTypeConverter.BrowsableLabelStyleAttribute style = new BrowsableTypeConverter.BrowsableLabelStyleAttribute(eBrowsablePropertyLabel);
            oCustomAttributes = new AttributeCollection(new Attribute[] { style });
        }
		
		private void BuildAttributes_CustomEventProperty()
		{
			UICustomEventEditor.DelegateAttribute attr = new UICustomEventEditor.DelegateAttribute(MethodDelegate);
			oCustomAttributes = new AttributeCollection(new Attribute[] {attr});
		}
		
		private object DataColumn
		{
			get
			{
				DataRow oRow = (System.Data.DataRow) oRef;
				if (oRow.RowState != DataRowState.Deleted)
				{
				if (oDatasource == null)
				{
					return oRow[sProp];
				}
				else
				{
					DataTable oLookupTable = oDatasource as DataTable;
					if (oLookupTable != null)
					{
						return oLookupTable.Select(sValueMember + "=" + oRow[sProp])[0][sDisplayMember];
					}
					else
					{
						Information.Err().Raise(Constants.vbObjectError + 513, null, "Bind of DataRow with a DataSource that is not a DataTable is not possible", null, null);
						return null;
					}
				}
			}
				else
				{
					return null;
				}
			}
			set
			{
				DataRow oRow = (System.Data.DataRow) oRef;
				if (oRow.RowState != DataRowState.Deleted)
				{
				if (oDatasource == null)
				{
					oRow[sProp] = value;
				}
				else
				{
					DataTable oLookupTable = oDatasource as DataTable;
					if (oLookupTable != null)
					{
						if (oLookupTable.Columns[sDisplayMember].DataType.Equals(System.Type.GetType("System.String")))
						{
							
							oRow[sProp] = oLookupTable.Select(oLookupTable.Columns[sDisplayMember].ColumnName + " = \'" + value + "\'")[0][sValueMember];
						}
						else
						{
							oRow[sProp] = oLookupTable.Select(oLookupTable.Columns[sDisplayMember].ColumnName + " = " + value)[0][sValueMember];
						}
					}
					else
					{
						Information.Err().Raise(Constants.vbObjectError + 514, null, "Bind of DataRow with a DataSource that is not a DataTable is impossible", null, null);
					}
				}
			}
		}
		}
		
		#endregion
		
		#region "Public properties"

        [Category("Appearance"), DisplayName("Name"), DescriptionAttribute("Display Name of the CustomProperty."), ParenthesizePropertyName(true), XmlElementAttribute("Name")]public string Name
        {
			get
			{
				return sName;
			}
			set
			{
				sName = value;
			}
		}

        [Category("Appearance"), DisplayName("ReadOnly"), DescriptionAttribute("Set read only attribute of the CustomProperty."), XmlElementAttribute("ReadOnly")]public bool IsReadOnly
        {
			get
			{
				return bIsReadOnly;
			}
			set
			{
				bIsReadOnly = value;
			}
		}

        [Category("Appearance"), DescriptionAttribute("Set visibility attribute of the CustomProperty.")]public bool Visible
        {
			get
			{
				return bVisible;
			}
			set
			{
				bVisible = value;
			}
		}

        [Category("Appearance"), DescriptionAttribute("Represent the Value of the CustomProperty.")]public object Value
        {
			get
			{
				if (bRef)
				{
                    if (oRef.GetType() == typeof(DataRow)  || oRef.GetType().IsSubclassOf(typeof(DataRow)))
						return this.DataColumn;
                    else
                        return Interaction.CallByName(oRef, sProp, CallType.Get, null);
				}
				else
				{
					return oValue;
				}
			}
			set
			{
				if (bRef)
				{
					if (oRef.GetType() == typeof(DataRow)  || oRef.GetType().IsSubclassOf(typeof(DataRow)))
							this.DataColumn = value;
                    else
                        Interaction.CallByName(oRef, sProp, CallType.Set, value);
				}
				else
				{
					oValue = value;
				}
			}
		}

        [Category("Appearance"), DescriptionAttribute("Set description associated with the CustomProperty.")]public string Description
        {
			get
			{
				return sDescription;
			}
			set
			{
				sDescription = value;
			}
		}

        [Category("Appearance"), DescriptionAttribute("Set category associated with the CustomProperty.")]public string Category
        {
			get
			{
				return sCategory;
			}
			set
			{
				sCategory = value;
			}
		}

        [XmlIgnore()]public System.Type Type
		{
			get
			{
				if (Value != null)
				{
					return Value.GetType();
				}
				else
				{
					if (oDefaultValue != null)
					{
						return oDefaultValue.GetType();
					}
					else
					{
						return oDefaultType;
					}
				}
            }
		}

        [XmlIgnore()]public AttributeCollection Attributes
		{
			get
			{
				return oCustomAttributes;
			}
			set
			{
				oCustomAttributes = value;
			}
		}

        [Category("Behavior"), DescriptionAttribute("Indicates if the property is browsable or not."), XmlElementAttribute(IsNullable = false)]public bool IsBrowsable
		{
			get
			{
				return bIsBrowsable;
			}
			set
			{
				bIsBrowsable = value;
				if (value == true)
				{
                    BuildAttributes_BrowsableProperty();
                }
			}
		}

		[Category("Appearance"), DisplayName("Parenthesize"), DescriptionAttribute("Indicates whether the name of the associated property is displayed with parentheses in the Properties window."), DefaultValue(false), XmlElementAttribute("Parenthesize")]public bool Parenthesize
		{
			get
			{
				return bParenthesize;
			}
			set
			{
				bParenthesize = value;
			}
		}

        [Category("Behavior"), DescriptionAttribute("Indicates the style of the label when a property is browsable."), XmlElementAttribute(IsNullable = false)]public BrowsableTypeConverter.LabelStyle BrowsableLabelStyle
        {
			get
			{
				return eBrowsablePropertyLabel;
			}
			set
			{
				bool Update = false;
				if (value != eBrowsablePropertyLabel)
				{
					Update = true;
				}
				eBrowsablePropertyLabel = value;
				if (Update)
				{
					BrowsableTypeConverter.BrowsableLabelStyleAttribute style = new BrowsableTypeConverter.BrowsableLabelStyleAttribute(value);
					oCustomAttributes = new AttributeCollection(new Attribute[] {style});
				}
			}
		}

        [Category("Behavior"), DescriptionAttribute("Indicates if the property is masked or not."), XmlElementAttribute(IsNullable = false)]public bool IsPassword
        {
			get
			{
				return bIsPassword;
			}
			set
			{
				bIsPassword = value;
			}
		}

        [Category("Behavior"), DescriptionAttribute("Indicates if the property represents a value in percentage."), XmlElementAttribute(IsNullable = false)]public bool IsPercentage
        {
			get
			{
				return bIsPercentage;
			}
			set
			{
				bIsPercentage = value;
			}
		}

        [Category("Behavior"), DescriptionAttribute("Indicates if the property uses a FileNameEditor converter."), XmlElementAttribute(IsNullable = false)]public bool UseFileNameEditor
        {
			get
			{
				return bUseFileNameEditor;
			}
			set
			{
				bUseFileNameEditor = value;
			}
		}

        [Category("Behavior"), DescriptionAttribute("Apply a filter to FileNameEditor converter."), XmlElementAttribute(IsNullable = false)]public string FileNameFilter
        {
			get
			{
				return sFilter;
			}
			set
			{
				bool UpdateAttributes = false;
				if (value != sFilter)
				{
					UpdateAttributes = true;
				}
				sFilter = value;
				if (UpdateAttributes)
				{
					BuildAttributes_FilenameEditor();
				}
			}
		}

        [Category("Behavior"), DescriptionAttribute("DialogType of the FileNameEditor."), XmlElementAttribute(IsNullable = false)]public UIFilenameEditor.FileDialogType FileNameDialogType
        {
			get
			{
				return eDialogType;
			}
			set
			{
				bool UpdateAttributes = false;
				if (value != eDialogType)
				{
					UpdateAttributes = true;
				}
				eDialogType = value;
				if (UpdateAttributes)
				{
					BuildAttributes_FilenameEditor();
				}
			}
		}

        [Category("Behavior"), DescriptionAttribute("Custom Choices list."), XmlIgnore()]public CustomChoices Choices
        {
			get
			{
				return oChoices;
			}
			set
			{
				oChoices = value;
				BuildAttributes_CustomChoices();
			}
		}

        [Category("Databinding"), XmlIgnore()]public object Datasource
        {
			get
			{
				return oDatasource;
			}
			set
			{
				oDatasource = value;
				BuildAttributes_ListboxEditor();
			}
		}

        [Category("Databinding"), XmlElementAttribute(IsNullable = false)]
        public string ValueMember
		{
			get
			{
				return sValueMember;
			}
			set
			{
				sValueMember = value;
				BuildAttributes_ListboxEditor();
			}
		}

        [Category("Databinding"), XmlElementAttribute(IsNullable = false)]
        public string DisplayMember
		{
			get
			{
				return sDisplayMember;
			}
			set
			{
				sDisplayMember = value;
				BuildAttributes_ListboxEditor();
			}
		}

        [Category("Databinding"), XmlElementAttribute(IsNullable = false)]
        public object SelectedValue
		{
			get
			{
				return oSelectedValue;
			}
			set
			{
				oSelectedValue = value;
			}
		}

        [Category("Databinding"), XmlElementAttribute(IsNullable = false)]
        public object SelectedItem
		{
			get
			{
				return oSelectedItem;
			}
			set
			{
				oSelectedItem = value;
			}
		}

        [Category("Databinding"), XmlElementAttribute(IsNullable = false)]
        public bool IsDropdownResizable
		{
			get
			{
				return bIsDropdownResizable;
			}
			set
			{
				bIsDropdownResizable = value;
				BuildAttributes_ListboxEditor();
			}
		}

        [XmlIgnore()]public UITypeEditor CustomEditor
		{
			get
			{
				return oCustomEditor;
			}
			set
			{
				oCustomEditor = value;
			}
		}

        [XmlIgnore()]public TypeConverter CustomTypeConverter
		{
			get
			{
				return oCustomTypeConverter;
			}
			set
			{
				oCustomTypeConverter = value;
			}
		}
				
		[XmlIgnore()]public object Tag
		{
			get
			{
				return oTag;
			}
			set
			{
				oTag = value;
			}
		}
		
		[XmlIgnore()]public object DefaultValue
		{
			get
			{
				return oDefaultValue;
			}
			set
			{
				oDefaultValue = value;
			}
		}
		
		[XmlIgnore()]public Type DefaultType
		{
			get
			{
				return oDefaultType;
			}
			set
			{
				oDefaultType = value;
			}
		}
		
		[XmlIgnore()]public UICustomEventEditor.OnClick OnClick
		{
			get
			{
				return MethodDelegate;
			}
			set
			{
				MethodDelegate = value;
				BuildAttributes_CustomEventProperty();
			}
		}
		
		#endregion
		
		#region "CustomPropertyDescriptor"
		public class CustomPropertyDescriptor : PropertyDescriptor
		{
			
			protected CustomProperty oCustomProperty;
			
			public CustomPropertyDescriptor(CustomProperty myProperty, Attribute[] attrs) : base(myProperty.Name, attrs)
			{
				if (myProperty == null)
				{
					oCustomProperty = null;
				}
				else
				{
					
					oCustomProperty = myProperty;
				}
			}
			
			public override bool CanResetValue(object component)
			{
				if ((oCustomProperty.DefaultValue != null)|| (oCustomProperty.DefaultType != null))
				{
					return true;
				}
				else
				{
					return false;
				}
			}
			
			public override System.Type ComponentType
			{
				get
				{
					return this.GetType();
				}
			}
			
			public override object GetValue(object component)
			{
				return oCustomProperty.Value;
			}
			
			public override bool IsReadOnly
			{
				get
				{
					return oCustomProperty.IsReadOnly;
				}
			}
			
			public override System.Type PropertyType
			{
				get
				{
					return oCustomProperty.Type;
				}
			}
			
			public override void ResetValue(object component)
			{
				oCustomProperty.Value = oCustomProperty.DefaultValue;
				this.OnValueChanged(component, EventArgs.Empty);
			}
			
			public override void SetValue(object component, object value)
			{
				oCustomProperty.Value = value;
				this.OnValueChanged(component, EventArgs.Empty);
			}
			
			public override bool ShouldSerializeValue(object component)
			{
				object oValue = oCustomProperty.Value;
				if ((oCustomProperty.DefaultValue != null)&& (oValue != null))
				{
					return ! oValue.Equals(oCustomProperty.DefaultValue);
				}
				else
				{
					return false;
				}
			}
			
			public override string Description
			{
				get
				{
					return oCustomProperty.Description;
				}
			}
			
			public override string Category
			{
				get
				{
					return oCustomProperty.Category;
				}
			}
			
			public override string DisplayName
			{
				get
				{
					return oCustomProperty.Name;
				}
			}
			
			public override bool IsBrowsable
			{
				get
				{
					return oCustomProperty.IsBrowsable;
				}
			}
			
			public object CustomProperty
			{
				get
				{
					return oCustomProperty;
				}
			}
		}
		#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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Germany Germany
Carsten started programming Basic and Assembler back in the 80’s when he got his first C64. After switching to a x86 based system he started programming in Pascal and C. He started Windows programming with the arrival of Windows 3.0. After working for various internet companies developing a linguistic text analysis and classification software for 25hours communications he is now working as a contractor.

Carsten lives in Hamburg, Germany with his wife and five children.

Comments and Discussions