Serg Serg - 2 months ago 17
C# Question

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

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.

Answer

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.

Comments