5
avril
2007
ICustomTypeDescriptor
avril
2007
Dans mon article sur le DataBinding avancé, je montre comment rajouter des propriétés virtuelles sans toucher au code d’une classe. Dans le cas où on puisse modifier le code de la classe, on peut aussi rajouter des propriétés virtuelles en utilisant l’interface ICustomTypeDescriptor.
Voici un exemple d’implémentation :
public class Person : ICustomTypeDescriptor
{
private DateTime _birthDay = new DateTime(1981, 11, 18);
public Person()
{
}
public DateTime BirthDay
{
get { return _birthDay; }
set { _birthDay = value; }
}
#region ICustomTypeDescriptor Members
public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
public string GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
public string GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
public PropertyDescriptor GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(this, true);
}
public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(attributes, true);
}
public EventDescriptorCollection GetEvents()
{
return GetEvents(null);
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
PropertyDescriptorCollection propsColl = TypeDescriptor.GetProperties(this, attributes, true);
List<PropertyDescriptor> props = new List<PropertyDescriptor>();
foreach (PropertyDescriptor prop in propsColl)
props.Add(prop);
props.Add(new AgePropertyDescriptor(typeof(Person).GetProperty("BirthDay"), "Age", null));
return new PropertyDescriptorCollection(props.ToArray());
}
public PropertyDescriptorCollection GetProperties()
{
return GetProperties(null);
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
#endregion
}
public class AgePropertyDescriptor : PropertyDescriptor
{
private PropertyInfo _birthDayPropertyInfo;
public AgePropertyDescriptor(PropertyInfo birthDayPropertyInfo, string name, Attribute[] attrs)
: base(name, attrs)
{
_birthDayPropertyInfo = birthDayPropertyInfo;
}
public override bool CanResetValue(object component)
{
return false;
}
public override Type ComponentType
{
get { return _birthDayPropertyInfo.ReflectedType; }
}
public override object GetValue(object component)
{
DateTime birthDay = (DateTime)_birthDayPropertyInfo.GetValue(component, null);
int yearsOld = DateTime.Now.Year - birthDay.Year;
if (DateTime.Now.Month < birthDay.Month)
yearsOld--;
else if ((DateTime.Now.Month == birthDay.Month) && (DateTime.Now.Day < birthDay.Day))
yearsOld--; 
return yearsOld;
}
public override bool IsReadOnly
{
get { return true; }
}
public override Type PropertyType
{
get { return typeof(int); }
}
public override void ResetValue(object component)
{
}
public override void SetValue(object component, object value)
{
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
}
{
private DateTime _birthDay = new DateTime(1981, 11, 18);
public Person()
{
}
public DateTime BirthDay
{
get { return _birthDay; }
set { _birthDay = value; }
}
#region ICustomTypeDescriptor Members
public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
public string GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
public string GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
public PropertyDescriptor GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(this, true);
}
public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(attributes, true);
}
public EventDescriptorCollection GetEvents()
{
return GetEvents(null);
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
PropertyDescriptorCollection propsColl = TypeDescriptor.GetProperties(this, attributes, true);
List<PropertyDescriptor> props = new List<PropertyDescriptor>();
foreach (PropertyDescriptor prop in propsColl)
props.Add(prop);
props.Add(new AgePropertyDescriptor(typeof(Person).GetProperty("BirthDay"), "Age", null));
return new PropertyDescriptorCollection(props.ToArray());
}
public PropertyDescriptorCollection GetProperties()
{
return GetProperties(null);
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
#endregion
}
public class AgePropertyDescriptor : PropertyDescriptor
{
private PropertyInfo _birthDayPropertyInfo;
public AgePropertyDescriptor(PropertyInfo birthDayPropertyInfo, string name, Attribute[] attrs)
: base(name, attrs)
{
_birthDayPropertyInfo = birthDayPropertyInfo;
}
public override bool CanResetValue(object component)
{
return false;
}
public override Type ComponentType
{
get { return _birthDayPropertyInfo.ReflectedType; }
}
public override object GetValue(object component)
{
DateTime birthDay = (DateTime)_birthDayPropertyInfo.GetValue(component, null);
int yearsOld = DateTime.Now.Year - birthDay.Year;
if (DateTime.Now.Month < birthDay.Month)
yearsOld--;
else if ((DateTime.Now.Month == birthDay.Month) && (DateTime.Now.Day < birthDay.Day))
yearsOld--; 
return yearsOld;
}
public override bool IsReadOnly
{
get { return true; }
}
public override Type PropertyType
{
get { return typeof(int); }
}
public override void ResetValue(object component)
{
}
public override void SetValue(object component, object value)
{
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
}
et pour le bind :
Person p = new Person();
dateTimePicker1.DataBindings.Add("Value", p, "BirthDay");
textBox2.DataBindings.Add("Text", p, "Age");
dateTimePicker1.DataBindings.Add("Value", p, "BirthDay");
textBox2.DataBindings.Add("Text", p, "Age");
Pour un autre exemple d’utilisation de l’interface ICustomTypeDescriptor, je vous conseille l’article de Mitch sur le DataBinding sur la base de registre.