Search code examples
c#editorpropertygrid

How to customize names in "Add" button dropdown in the PropertyGrid custom collection editor


I'm using PropertyGrid to edit a collection. An object with the collection is defined as following:

class ObjWithCollection
{
    [Editor(typeof(MyCustomCollectionEditor),typeof(UITypeEditor))]
    public List<ItemBase> collection { get; set; } = new List<ItemBase>();//ItemBase is abstract
}

The collection contains the objects of two types, derived from ItemBase class: Item1 and Item2. These classes defined as following:

public abstract class ItemBase
{
    public string Name { get; set; }
    public ItemBase() { }
    public ItemBase(string name) { Name = name; }
}

public class Item1:ItemBase
{
    public Item1():base("Item 1 name"){}
}

[DisplayName("item2 test display name")]
public class Item2:ItemBase
{
    public Item2() : base("item 2 name") { }
}

To be able to add new items to the collection via the editor, I also defined the custom collection editor class and override CreateNewItemTypes to list all types suitable for collection:

class MyCustomCollectionEditor : CollectionEditor
{
    public MyCustomCollectionEditor(Type type) : base(type){}
    protected override Type[] CreateNewItemTypes()
    {
        return new Type[] { typeof(Item1), typeof(Item2) };
    }
}

Then I bind my custom editor to the ObjWithCollection.collection property with Editor attibute (see ObjWithCollection.collection definition).

This works fine and I able to edit my collection, including the adding of the new items. The Add button has a dropdown which allows user to select the type of element to add. editor window http://i.share.pho.to/31d50d09_o.png

But in the Add button dropdown the items called "Item1" and "Item2" and I can't change this names. I tried DisplayName attribute, ToString override, but no luck.

So, the qustion is how to I can output the custom names for the elements of the Add button menu.


Solution

  • I don't think this is possible directly from the property grid's code. However, you can use a TypeDelegator to trick the system and force it to use for example your DisplayName attribute in lieu of the type's Name property it uses by default.

    1) create a custom TypeDelegator, like this:

    class MyTypeDelegator : TypeDelegator
    {
        public MyTypeDelegator(Type delegatingType)
            : base(delegatingType)
        {
        }
    
        public override string Name
        {
            get
            {
                var dna = (DisplayNameAttribute)typeImpl.GetCustomAttribute(typeof(DisplayNameAttribute));
                return dna != null ? dna.DisplayName : typeImpl.Name;
            }
        }
    }
    

    2) modify CreateNewItemTypes() like this:

        protected override Type[] CreateNewItemTypes()
        {
            return new Type[] { new MyTypeDelegator(typeof(Item1)), new MyTypeDelegator(typeof(Item2)) };
        }
    

    Now, you should see the display names instead of the name in the menu.