|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
When Formatable is False, only Text is visible
But when Formatable is True, Text is protected and Format shows up ;) IntroductionIn my work very often I have to resolve this kind of problems so after some reading, copying, googling, etc... Wow idea comes up! BackgroundImplementingICustomTypeDescriptor interface on any class we can provide properties to PropertyGrid control in dynamic way. So lets code that interface.public class SomeClass : ICustomTypeDescriptor
{
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
/* ... so we arrive at ... */
public PropertyDescriptorCollection GetProperties()
{
// use new implemented class to get properties
return DynamicTypeDescriptor.GetProperties(this);
}
}
So, what is DynamicTypeDescriptor class here for? This class substitutes standard TypeDescriptor.GetProperties(...) behaviour.public static PropertyDescriptorCollection GetProperties(object component)
{
// hold all properties found
PropertyInfo[] propsInfo = component.GetType().GetProperties(BindingFlags.Public|BindingFlags.Instance);
ArrayList list = new ArrayList(propsInfo.Length);
// loop properties
foreach(PropertyInfo prop in propsInfo)
{
// get all property attributes and check for "dynamics"
ArrayList attributeList = new ArrayList();
foreach(Attribute attrib in prop.GetCustomAttributes(true))
{
// if is dynamic one then evaluate it
if (attrib is DependsOnPropertyAttribute)
attributeList.Add(((DependsOnPropertyAttribute)attrib).Evaluate(component));
else
attributeList.Add(attrib);
}
list.Add(new PropertyInfoDescriptor(prop, (Attribute[])attributeList.ToArray(typeof(Attribute))));
}
return new PropertyDescriptorCollection((PropertyDescriptor[])list.ToArray(typeof(PropertyDescriptor)));
}
You may said, but what /// <summary> /// Base class for all dynamic attributes. /// Only properties can use this attribute. /// </summary> [AttributeUsage(AttributeTargets.Property)] public abstract class DependsOnPropertyAttribute : Attribute { /// <summary> /// Create new instance of class /// </summary> /// <param name="expression">Property name</param> protected DependsOnPropertyAttribute(string property) : base() { _property = property; _index = null; } /// <summary> /// Create new instance of class /// </summary> /// <param name="property">Property name</param> /// <param name="index">Property element index</param> protected DependsOnPropertyAttribute(string property, int index) { _property = property; _index = new object[] {index}; } private string _property; private object[] _index; /// <summary> /// Evaluate attribute using property container supplied /// </summary> /// <param name="container">Object that contains property to evaluate</param> /// <returns>Dynamically evaluated attribute</returns> public Attribute Evaluate(object container) { return OnEvaluateComplete(RuntimeEvaluator.Eval(container, _property, _index)); } /// <summary> /// Specific dynamic attribute check implementation /// </summary> /// <param name="value">Evaluated value</param> /// <returns>Dynamically evaluated attribute</returns> protected abstract Attribute OnEvaluateComplete(object value); private class RuntimeEvaluator { public static object Eval(object container, string property, object[] index) { PropertyInfo pInfo = container.GetType().GetProperty(property); if (pInfo != null) return pInfo.GetValue(container, index); return null; } } } This class defines abstract implemenentation for all DynamicAttributes. In my example there are two implemented attributes: protected override Attribute OnEvaluateComplete(object value) { Attribute output; try { // check if value is provided if (value == null) value = false; // asume default // create attribute output = new ReadOnlyAttribute((bool)value); } catch { output = new ReadOnlyAttribute(false); } return output; } Using the codeTo use code you will have to create some class with public properties. On property that others depends on, insert Points of InterestYou can see how to implement History21/03/2007 - First release.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||