PropertyGrid with Custom PropertyDescriptor

巧了我就是萌 提交于 2019-12-07 07:14:47

问题


I've been struggling quite a bit to get custom PropertyDescriptors to work the way I want with a PropertyGrid.

The premise:

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

The third bullet I can get working quite easily (see image below).

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

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

I'd like to allow users the ability to edit the members of each Animal in the PropertyGrid (Age, Type, Location, and Name). How can I achieve this? I assume there will need to be a custom editor of some type. Honestly, however, I have no idea where to get started as Googling hasn't turned up much for this.

Here are the tutorials I followed to get to this point:

  • Add (Remove) Items to (from) PropertyGrid at Runtime
  • Using PropertyGrid with a dictionary object (this tutorial seems really old)

And if you need it, here's 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 am aware that the code is a bit ridiculous (Animals with names, animal groups, etc).


回答1:


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 Customized display of collection data in a PropertyGrid helpful.



来源:https://stackoverflow.com/questions/11892064/propertygrid-with-custom-propertydescriptor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!