You can do this by having your class implement ICustomPropertyDescriptor.
This enables you to change the display names of properties, even add or
remove properties that you choose.
After my signature is an article from Well Formed that explains this
process. The rest of the article explains how to create dynamic properties.
--
Bob Powell [MVP]
Visual C#, System.Drawing
Image transition effects, automatic persistent configuration and
design time mouse operations all in April's issue of Well Formed
http://www.bobpowell.net/wellformed.htm
Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdiplus_faq.htm
The GDI+ FAQ RSS feed:
http://www.bobpowell.net/faqfeed.xml
Windows Forms Tips and Tricks RSS:
http://www.bobpowell.net/tipstricks.xml
Bob's Blog:
http://royo.is-a-geek.com/siteFeeder/GetFeed.aspx?FeedId=41
----------------------------------------------------------------------------
-------------------------------------------
The TypeDescriptor base class can reflect all the members of a class and
more specifically, retrieve its properties as a PropertyDescriptorCollection
containing one or more PropertyDescriptor objects. If the class needs to
return customized reflection information the class must implement the
ICustomTypeDescriptor interface. This interface enables you to modify the
reflection information returned whenever a class is examined.
A PropertyDescriptor contains information about the type of property, it's
name , it's display name which can be different from it's real name, the
type converters used for the property, what attributes the property has and
some other information that is not important to this discussion. To change
the way a property is displayed a mechanism for marking a property in some
way is needed.
The framework provides attributes for this purpose. Attributes are a way of
tagging classes, properties, methods and events with information, known as
metadata, before the class is compiled. Once it is compiled to code, those
attributes can be read but not modified by the runtime system. Attributes
that enable new metadata, such as a FreindlyNameAttribute can be created and
used to tag all the properties we want to display differently.
Listing 1 shows the FriendlyNameAttribute.
Now that the properties may be tagged with friendly names, the property
descriptors passed to the PropertyGrid need to be able to use that
information. The PropertyDescriptor returned from the standard
TypeDescriptor.GetProperties method knows nothing of the new attribute and
had read-only properties so it's not possible to intercept or override the
information. Instead, a wrapper class, based on PropertyDescriptor and
containing the original PropertyDescriptor is used. Whenever information is
read from the derived property descriptor, it passes on the information in
the inner descriptor except where the DisplayName property is concerned.
That returns the contents of the attribute created for the purpose.
Listing 2 shows the FriendlyNamePropertyDescriptor.
The classes that are to be enhanced in the PropertyGrid must know how to
return the correct information, more specifically, the newly enhanced
FriendlyNamePropertyDescriptor. To do this, the class must implement
ICustomTypeDescriptor. This interface provides methods for returning custom
metadata whenever a class is interrogated. Like the
FriendlyNamePropertyDescriptor, the implementation used in this example will
return most of it's information simply by passing on that of the standard
TypeDescriptor. When it comes to properties however, a collection of
FriendlyNamePropertyDescriptors is assembled and returned instead. The
PropertyGrid will then show the contents of the DisplayName property which
is tagged with the FriendlyNameAttribute.
Listing 3 shows a base class implementing ICustomTypeDescriptor and another
which returns the custom property descriptor collection.
----------------------------------------------------------------------------
---------------------------------------------------------
Listing1
The FriendlyNameAttribute.
[
AttributeUsage(AttributeTargets.Property),
]
class FriendlyNameAttribute : Attribute
{
string _name;
public string Name
{
get{return _name;}
set{_name=value;}
}
public FriendlyNameAttribute(string name)
{
_name=name;
}
}
----------------------------------------------------------------------------
---------------------------------------------------------
Listing2
public class FriendlyNamePropertyDescriptor : PropertyDescriptor
{
private PropertyDescriptor basePropertyDescriptor;
public FriendlyNamePropertyDescriptor(PropertyDescriptor pd) : base(pd)
{
this.basePropertyDescriptor=pd;
}
public override void AddValueChanged(object component, EventHandler
handler)
{
this.basePropertyDescriptor.AddValueChanged (component, handler);
}
public override AttributeCollection Attributes
{
get
{
return this.basePropertyDescriptor.Attributes;
}
}
public override bool CanResetValue(object component)
{
return this.basePropertyDescriptor.CanResetValue(component);
}
public override string Category
{
get
{
return this.basePropertyDescriptor.Category;
}
}
public override Type ComponentType
{
get
{
return this.basePropertyDescriptor.ComponentType;
}
}
public override TypeConverter Converter
{
get
{
return this.basePropertyDescriptor.Converter;
}
}
public override string Description
{
get
{
return this.basePropertyDescriptor.Description;
}
}
public override bool DesignTimeOnly
{
get
{
return this.basePropertyDescriptor.DesignTimeOnly;
}
}
//This method is overridden to take notice of the FriendlyNameAttribute
//if it has been applied to the property
public override string DisplayName
{
get
{
foreach(Attribute a in this.AttributeArray)
{
if(a is FriendlyNameAttribute)
{
return ((FriendlyNameAttribute)a).Name;
}
}
return this.basePropertyDescriptor.DisplayName;
}
}
public override bool Equals(object obj)
{
return this.basePropertyDescriptor.Equals (obj);
}
public override PropertyDescriptorCollection GetChildProperties(object
instance, Attribute[] filter)
{
return this.basePropertyDescriptor.GetChildProperties (instance,
filter);
}
public override object GetEditor(Type editorBaseType)
{
return this.basePropertyDescriptor.GetEditor (editorBaseType);
}
public override int GetHashCode()
{
return this.basePropertyDescriptor.GetHashCode ();
}
public override object GetValue(object component)
{
return this.basePropertyDescriptor.GetValue(component);
}
public override bool IsBrowsable
{
get
{
return this.basePropertyDescriptor.IsBrowsable;
}
}
public override bool IsLocalizable
{
get
{
return this.basePropertyDescriptor.IsLocalizable;
}
}
public override bool IsReadOnly
{
get
{
return this.basePropertyDescriptor.IsReadOnly;
}
}
public override string Name
{
get
{
return this.basePropertyDescriptor.Name;
}
}
public override Type PropertyType
{
get
{
return this.basePropertyDescriptor.PropertyType;
}
}
public override void RemoveValueChanged(object component, EventHandler
handler)
{
this.basePropertyDescriptor.RemoveValueChanged (component, handler);
}
public override void ResetValue(object component)
{
this.basePropertyDescriptor.ResetValue(component);
}
public override void SetValue(object component, object value)
{
this.basePropertyDescriptor.SetValue(component, value);
}
public override bool ShouldSerializeValue(object component)
{
return this.basePropertyDescriptor.ShouldSerializeValue(component);
}
public override string ToString()
{
return this.basePropertyDescriptor.ToString ();
}
}
----------------------------------------------------------------------------
---------------------------------------------------------
Listing3
//A base class that can be used to create derived classes which use
friendly names
//The methods and properties normally return data from the standard
TypeDescriptor
//except the methods that return a PropertyDescriptorCollection.
public class FriendlyNameBase : ICustomTypeDescriptor
{
/// <summary>
/// Creates a collection of FriendlyPropertyDescriptors
/// </summary>
/// <param name="attributes">An array of attributes used to select the
properties required.
/// Normally contains a BrowsableAttribute used to select only the
browsable properties from the class</param>
/// <returns>A collection of modified property descriptors</returns>
protected PropertyDescriptorCollection GetFriendlyProperties(Attribute[]
attributes)
{
PropertyDescriptorCollection pdc =
TypeDescriptor.GetProperties(this,attributes,true);
PropertyDescriptorCollection finalProps=new
PropertyDescriptorCollection(new PropertyDescriptor[0]);
foreach(PropertyDescriptor pd in pdc)
finalProps.Add(new FriendlyNamePropertyDescriptor(pd));
return finalProps;
}
#region ICustomTypeDescriptor Members
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this,true);
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this,attributes,true);
}
EventDescriptorCollection
System.ComponentModel.ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents(this,true);
}
public string GetComponentName()
{
return TypeDescriptor.GetComponentName(this,true);
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(this,true);
}
public PropertyDescriptorCollection GetProperties(Attribute[]
attributes)
{
return this.GetFriendlyProperties(attributes);
}
PropertyDescriptorCollection
System.ComponentModel.ICustomTypeDescriptor.GetProperties()
{
return this.GetFriendlyProperties(new Attribute[0]);
}
public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this,editorBaseType,true);
}
public PropertyDescriptor GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(this,true);
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this,true);
}
public string GetClassName()
{
return TypeDescriptor.GetClassName(this,true);
}
#endregion
}
////////////////////////////////////////////////////////////////////////////
//////////
//A class based on the FriendlyNameBase which is used
//to populate the property grid and display friendly named properties
public class DemoClass : FriendlyNameBase
{
string _notAVeryFriendlyName;
public string NotAVeryFriendlyName
{
get{return _notAVeryFriendlyName;}
set{_notAVeryFriendlyName=value;}
}
string _aVeryFriendlyNameIndeed;
[FriendlyName("A Friendly Name")] //Note the use of this attribute
public string AVeryFriendlyNameIndeed
{
get{return _aVeryFriendlyNameIndeed;}
set{_aVeryFriendlyNameIndeed=value;}
}
}
Martin Montgomery said:
I have, for example, a property called myProperty. I would like, when
using a property grid to display the property name as "My Property". Is this
possible. Is there an attribute etc.