When Formatable is False, only Text is visible
But when Formatable is True, Text is protected and Format shows up
Introduction
In my work, very often I have to resolve this kind of problem. So after some reading, copying, Googling, etc... wow, an idea comes up!
Background
Implementing ICustomTypeDescriptor
interface on any class, we can provide properties to PropertyGrid
control in a dynamic way. So let's code that interface.
public class SomeClass : ICustomTypeDescriptor
{
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
public PropertyDescriptorCollection GetProperties()
{
return DynamicTypeDescriptor.GetProperties(this);
}
}
So, what is DynamicTypeDescriptor
class here for? This class substitutes standard TypeDescriptor.GetProperties(...)
behaviour.
public static PropertyDescriptorCollection GetProperties(object component)
{
PropertyInfo[] propsInfo =
component.GetType().GetProperties(BindingFlags.Public|BindingFlags.Instance);
ArrayList list = new ArrayList(propsInfo.Length);
foreach(PropertyInfo prop in propsInfo)
{
ArrayList attributeList = new ArrayList();
foreach(Attribute attrib in prop.GetCustomAttributes(true))
{
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 say, but what does DependsOnPropertyAttribute
stand for?
[AttributeUsage(AttributeTargets.Property)]
public abstract class DependsOnPropertyAttribute : Attribute
{
protected DependsOnPropertyAttribute(string property) : base()
{
_property = property;
_index = null;
}
protected DependsOnPropertyAttribute(string property, int index)
{
_property = property;
_index = new object[] {index};
}
private string _property;
private object[] _index;
public Attribute Evaluate(object container)
{
return OnEvaluateComplete(RuntimeEvaluator.Eval(container, _property, _index));
}
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
implementation for all DynamicAttributes
. In my example, there are two implemented attributes: DynamicBrowsableAttribute
and DynamicReadOnlyAttribute
.
A sample implementation for abstract OnEvaluateComplete
method is shown below:
protected override Attribute OnEvaluateComplete(object value)
{
Attribute output;
try
{
if (value == null)
value = false;
output = new ReadOnlyAttribute((bool)value);
}
catch
{
output = new ReadOnlyAttribute(false);
}
return output;
}
Using the Code
To use the code, you will have to create some class with public
properties. On property that others depends on, insert RefreshProperties(RefreshProperties.All)
attribute so property grid will be auto refreshed and will requery your properties. To provide dynamic functionality, implement
ICustomTypeDescriptor
interface in your class. From now on, you dynamically provide properties to property grid, easy yeah!
Insert DynamicAttribute
on dynamic properties like this DynamicBrowsable("property name")
, where property name is substituted with name of property that this one depends on. In my case property Format
has DynamicBrowsable("Formatable")
attribute set.
So now you will have to create an instance of your class and select it in the property grid control.
Points of Interest
You can see how to implement the ICustomTypeDescriptor
interface, how to provide new Attributes
and how to play with PropertyGrid
control.
History
- 21/03/2007 - First release