LOGIN    REGISTER    YOUR CART

homepage
VisualHint's blog
2022
Mar24

Smart PropertyGrid makes it super easy to select an item in a collection property

On internet, I have often seen the following question:

I have a collection (a list or a dictionary) and I would like to show a property in the PropertyGrid that allows me to select an item from the collection.

This kind of question can be seen in these 2 examples:

I then wondered if it was possible to provide a solution without having to modify SPG. This was quickly found by using the PropertyCreated event and calling PropertyValue.ResetDisplayedValues with the correct values to place in the list.
As the question is recurrent on the net, I decided to integrate my solution inside SPG. In the client application, you just have to apply the CollectionPropertySelector attribute to a property that will act as a selected index in a list or as a selected key in a dictionary. Only one parameter is required: the name of the collection in the class. Here is an example in a TestClass:

public TestClass()
{
    PlanetList = new List<Planet> {
        new Planet("Mercury"),
        new Planet("Venus"),
        new Planet("Earth"),
        new Planet("Mars"),
        new Planet("Jupiter"),
        new Planet("Saturn")};
    MyPlanet1 = 2;

    PlanetDictionary = new Dictionary<string, Planet> {
        { "Mercury", new Planet(1) },
        { "Venus", new Planet(2) },
        { "Earth", new Planet(3) },
        { "Mars", new Planet(4) },
        { "Jupiter", new Planet(5) },
        { "Saturn", new Planet(6) },
    };
    MyPlanet2 = "Earth";
}

[Browsable(false)]
public List<Planet> PlanetList { get; set; }

[DisplayName("Home planet")]
[CollectionPropertySelector(nameof(PlanetList))]
public int MyPlanet1 { get; set; }

[Browsable(false)]
public Dictionary<string, Planet> PlanetDictionary { get; set; }

[DisplayName("Secondary planet")]
[CollectionPropertySelector(nameof(PlanetDictionary))]
public string MyPlanet2 { get; set; }

As you can see, we apply Browsable(false) to the collection to not include it in the grid, then we apply the CollectionPropertySelector attribute to a property of type int for the list and to a property of type string for the dictionary (because the key is of type int). For this to work, a little extra tooling is required. The class that is in the list (Planet) must have a ToString() method that returns a representation of the instance. It is also possible to use a TypeConverter for the same purpose. In the dictionary case, this is not necessary because the Planet class is used as the Value and not as the Key.

In order for the CollectionPropertySelector attribute to act when the attached property is created, I had to add a new Hook to SPG and create a parent class to this attribute that will react on the PropertyCreated event. Just before the event is triggered, I look for any attributes of this type and call their OnPropertyCreated method. You can use the PropertyCreatedHandlerAttribute base class with your own attributes to react to this event. Later on, I will add the same mechanism for other types of events, allowing you to build a set of attributes that can act at the right time.

You can right now find this feature in SPG for .Net 6 version 4.0.0-rc.5 (available on nuget.org).

Do you have some small challenges like this to submit to me? Let me know if you have some needs and you are not sure if SPG can help you right away or thanks to a new feature I could add for you.