Knowing that it was a PropertyGrid was the first step.
Being able to create a custom class from the custom configuration sections
that we use in our Web.config and App.Config files was the next task (We
don't only use appsettings - we have two specific custom configuration
sections). I tried to find the original posting in order to thank Venu
Madhav for the posting below. Hopefully he won't mind the reposting here.
Venu Madhav's CustomClass which let's you add properties to the class at
runtime - which in turn can then be used to populate the gird. I add the
properties to the class using an XmlDocument to read the nodes and
attributes for our custom configuration sections. Very cool.
using System;
using System.Management;
using System.Data;
using System.ComponentModel;
using System.Management.Instrumentation;
using System.Collections;
namespace PropGrid
{
/// <summary>
/// CustomClass implements ICustomTypeDescriptor and derives
ExpandableObjectConverter
/// This class can be instantiated and properties to this class can
be added to it dynamically.
/// Use AddProperty(string propName, System.Type propType, string
propDesc, object propValue) to add a property.
/// </summary>
[TypeConverter(typeof(ExpandableObjectConverter))]
class CustomClass : Component, ICustomTypeDescriptor
{
/// <summary>
/// Constructor of CustomClass which initializes the DataTable.
/// </summary>
public CustomClass()
{
myTable = new DataTable("Properties");
categoryList = new ArrayList();
dataTypeList = new ArrayList();
}
/// <summary>
/// Adds a property into the CustomClass.
/// </summary>
/// <param name="propName">Name of the property that needs to be
added.</param>
/// <param name="propType">DataType of the property that needs to be
added.</param>
/// <param name="propDesc">Description of the property that needs to
be added.</param>
/// <param name="propValue">Value of the property that needs to be
added.</param>
public void AddProperty(string propName, System.Type propType,
string propDesc, object propValue, string categoryItem, bool isArray)
{
DataColumn myDC = new DataColumn(propName, propType);
myDC.Caption = propDesc;
myTable.Columns.Add(myDC);
if(myTable.Rows.Count == 0)
{
DataRow myDR = myTable.NewRow();
myTable.Rows.Add(myDR);
}
this[propName] = propValue;
categoryList.Add(categoryItem);
dataTypeList.Add(isArray);
}
/// <summary>
/// Adds a property into the CustomClass from the given
PropertyData.
/// </summary>
/// <param name="myPD">The PropertyData which needs to needs to be
added to the CustomClass.</param>
public void AddProperty(PropertyData myPD, string categoryItem, bool
isArray)
{
DataColumn myDC = new DataColumn(myPD.Name, myPD.GetType());
myDC.Caption = myPD.Name;
myTable.Columns.Add(myDC);
if(myTable.Rows.Count == 0)
{
DataRow myDR = myTable.NewRow();
myTable.Rows.Add(myDR);
}
this[myPD.Name] = myPD.Value;
categoryList.Add(categoryItem);
dataTypeList.Add(isArray);
}
ArrayList categoryList;
ArrayList dataTypeList;
public object this[string name]
{
get
{
return myTable.Rows[0][name];
}
set
{
myTable.Rows[0][name] = value;
}
}
private DataTable myTable;
private PropertyDescriptorCollection privateProp;
/// <summary>
///
/// </summary>
/// <returns></returns>
public string GetClassName()
{
return(TypeDescriptor.GetClassName(this, true));
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public AttributeCollection GetAttributes()
{
return(TypeDescriptor.GetAttributes(this, true));
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public string GetComponentName()
{
return(TypeDescriptor.GetComponentName(this, true));
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public TypeConverter GetConverter()
{
return(TypeDescriptor.GetConverter(this, true));
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public EventDescriptor GetDefaultEvent()
{
return(TypeDescriptor.GetDefaultEvent(this, true));
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public PropertyDescriptor GetDefaultProperty()
{
PropertyDescriptorCollection myProps = GetAllProperties();
if(myProps.Count > 0)
return(myProps[0]);
else
return(null);
}
/// <summary>
///
/// </summary>
/// <param name="editorBaseType"></param>
/// <returns></returns>
public object GetEditor(Type editorBaseType)
{
return(TypeDescriptor.GetEditor(this, editorBaseType,true));
}
/// <summary>
///
/// </summary>
/// <param name="attributes"></param>
/// <returns></returns>
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return(TypeDescriptor.GetEvents(this, attributes, true));
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public EventDescriptorCollection GetEvents()
{
return(TypeDescriptor.GetEvents(this, true));
}
/// <summary>
///
/// </summary>
/// <param name="attributes"></param>
/// <returns></returns>
public PropertyDescriptorCollection GetProperties(Attribute[]
attributes)
{
return(GetAllProperties());
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public PropertyDescriptorCollection GetProperties()
{
return(GetAllProperties());
}
/// <summary>
///
/// </summary>
/// <param name="pd"></param>
/// <returns></returns>
public object GetPropertyOwner(PropertyDescriptor pd)
{
return(this);
}
private PropertyDescriptorCollection GetAllProperties()
{
if(privateProp == null)
{
privateProp = new PropertyDescriptorCollection(new
PropertyDescriptor[]{});
int i = 0;
foreach(DataColumn myDC in myTable.Columns)
{
AddNewColumn myANC = new
AddNewColumn(myDC,
categoryList.ToString(), (bool)dataTypeList);
privateProp.Add(myANC);
PropertyDescriptorCollection myPDC =
myANC.GetChildProperties();
i++;
}
}
return privateProp;
}
public class AddNewColumn : PropertyDescriptor
{
private DataColumn myDC;
private string insertCategory;
private Type myType;
private bool isExpandable;
public AddNewColumn(DataColumn thisDC, string insCat, bool
expandable):base(thisDC.ColumnName, new Attribute[]{})
{
myDC = thisDC;
myType = thisDC.GetType();
insertCategory = insCat;
isExpandable = expandable;
}
public override System.Type ComponentType
{
get
{
return null;
}
}
public override string Category
{
get
{
return insertCategory;
}
}
public override bool IsReadOnly
{
get
{
return myDC.ReadOnly;
}
}
public override System.Type PropertyType
{
get
{
if(isExpandable)
return myType;
else
return myDC.DataType;
}
}
public override bool CanResetValue ( object component )
{
return true;
}
public override object GetValue ( object component )
{
CustomClass myCC = component as CustomClass;
if(myCC != null)
return myCC[myDC.ColumnName];
else
throw new ArgumentException ( "Component is not derived
from
DynamicProperties" );
}
public override void SetValue ( object component , object
value )
{
CustomClass myCC = component as CustomClass;
if(myCC != null)
myCC[myDC.ColumnName] = value;
else
throw new ArgumentException ( "Component is not derived
from
DynamicProperties" );
}
public override void ResetValue ( object component )
{
CustomClass myCC = component as CustomClass;
if(myCC != null)
myCC[myDC.ColumnName] = null;
else
throw new ArgumentException ( "Component is not derived
from
DynamicProperties" );
}
public override bool ShouldSerializeValue ( object component )
{
return false;
}
public override string Description
{
get
{
return myDC.Caption;
}
}
}
}
}