PropertyGrid with Custom PropertyDescriptor

I try a lot to get custom PropertyDescriptors to work the way I want with a PropertyGrid.

Premise:

  • I have a class called "Animal" that contains the properties Age , Type , Location and Name .
  • I have another class called "AnimalGroup" that contains a List<Animal> where animals are stored. The class member containing this list is called Members .
  • In the user interface of the program, an element of the PropertyGrid form will display the Animals list in the AnimalGroup, which is assigned to the PropertGrid SelectedObject property.

The third bullet I can easily work (see image below).

PropertyGrid showing the members of an AnimalGroup.

The AnimalGroup class implements the ICustomTypeDescriptor interface to achieve the functionality of the Animals enumeration in a member of the Members class.

Unfortunately, as you can see in the image above, the property value is just the value returned from the Animal ToString method.

I want to allow users to edit the members of each Animal in the PropertyGrid (Age, Type, Location and Name). How can i achieve this? I assume that this will require a special editor of some kind. Honestly, however, I have no idea where to start, since Googling is not too much for this.

The following are the tutorials that I read to get to this point:

And if you need it, here is my code (using .NET 4.0):

Animal.cs

 public class Animal { private String _Name; public String Name { get { return _Name; } set { _Name = value; } } private String _Type; public String Type { get { return _Type; } set { _Type = value; } } private String _Age; public String Age { get { return _Age; } set { _Age = value; } } private String _Location; public String Location { get { return _Location; } set { _Location = value; } } public override string ToString() { return this.Name + " - " + this.Type; } } 

AnimalGroup.cs

 public class AnimalGroup : ICustomTypeDescriptor { public List<Animal> Members; public AnimalGroup() { this.Members = new List<Animal>(); } 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 null; } public object GetEditor(Type editorBaseType) { return TypeDescriptor.GetEditor(this, editorBaseType, true); } public EventDescriptorCollection GetEvents(Attribute[] attributes) { return TypeDescriptor.GetEvents(this, attributes, true); } public EventDescriptorCollection GetEvents() { return TypeDescriptor.GetEvents(this, true); } public PropertyDescriptorCollection GetProperties(Attribute[] attributes) { PropertyDescriptor[] pds = new PropertyDescriptor[this.Members.Count]; int i = 0; foreach (Animal a in this.Members) { pds[i] = new AnimalPropertyDescriptor(a, attributes); i++; } return new PropertyDescriptorCollection(pds); } public PropertyDescriptorCollection GetProperties() { return this.GetProperties(new Attribute[0]); } public object GetPropertyOwner(PropertyDescriptor pd) { return this.Members; } } 

AnimalPropertyDescriptor.cs

 public class AnimalPropertyDescriptor : PropertyDescriptor { private Animal property; public AnimalPropertyDescriptor(Animal target, Attribute[] attrs) : base(target.Name, attrs) { this.property = target; } public override bool CanResetValue(object component) { return false; } public override Type ComponentType { get { return null; } } public override object GetValue(object component) { return property; } public override bool IsReadOnly { get { return false; } } public override Type PropertyType { get { return this.property.GetType(); } } public override void ResetValue(object component) { // Not relevant. } public override void SetValue(object component, object value) { this.property = (Animal)value; } public override bool ShouldSerializeValue(object component) { return false; } } 

FYI, I know that the code is a little ridiculous (animals with names, groups of animals, etc.).

+4
source share
1 answer

It looks like you are missing a converter:

 internal class AnimalConverter : ExpandableObjectConverter { public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string) && value is Animal) { Animal a = (Animal)value; return a.ToString(); } return base.ConvertTo(context, culture, value, destinationType); } } 

Then decorate your animal:

 [TypeConverter(typeof(AnimalConverter))] public class Animal {...} 

Found this code project a useful display of collection data in a PropertyGrid .

+3
source

All Articles