Search code examples
c#.netwinformspropertygrid

PropertyGrid - Show properties of a specific Interface, not all properties


I am currently facing an (IMHO) strange behavior of the PropertyGrid:

I have an interface (ITest) that defines some properties. This interface will be implemented by a Component or a Panel (TestImpl). The other part is a Component (TestComponent) that has a public property of the interface type. A default implementation will be assigend to that property and it could be changed by the user to a more specific implementation. If I add this TestComponent to a Form, I would expect, that by expanding the public-interface-property, only the properties declared in the interface will be visible - instead all properties of the Panel or Component are visible...

public interface ITest
{
    string AAAAA { get; set; }
}

public class TestImpl: Panel, ITest
{
    public string AAAAA { get; set; }
}

public class TestComponent : Component
{
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public ITest Obj { get; set; }
    public TestComponent()
    {
        Obj = new TestImpl();
    }
}

// To reproduce create a simple Form, add a PropertyGrid, create and assign the TestComponent
public partial class Form4 : Form
{
    public Form4()
    {
        InitializeComponent();

        var comp = new TestComponent();
        comp.Obj.AAAAA = "Some Text";

        propertyGrid1.SelectedObject = comp;
    }
}

Is there a way to show only the interface-properties?


Solution

  • PropertyGrid by default shows display name of all public properties of your control which are browsable. It uses TypeDescriptor of your object to ask about its metadata including its browsable properties and their display names.

    To customize this behavior you need to register a new TypeDescriptionProvider for your object.

    Example

    In the following example, I've created a MyPanel control which derives from Panel and implements IMyInterface. Then I created a custom MyTypeDescriptionProvider<T> and set MyTypeDescriptionProvider<IMyInterface> as TypeDescriptionProvider of my control.

    This way, when you set an instance of MyPanel as SelectedObject of the PropertyGrid, only properties of IMyInterface will be shown in PropertyGrid.

    using System;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    public interface IMyInterface
    {
        string MyProperty1 { get; set; }
        string MyProperty2 { get; set; }
    }
    
    public class MyTypeDescriptionProvider<T> : TypeDescriptionProvider
    {
        public MyTypeDescriptionProvider() : base(TypeDescriptor.GetProvider(typeof(T))) { }
    
        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType,
            object instance)
        {
            return base.GetTypeDescriptor(typeof(T), instance);
        }
    }
    
    [TypeDescriptionProvider(typeof(MyTypeDescriptionProvider<IMyInterface>))]
    public class MyPanel : Panel, IMyInterface
    {
        public string MyProperty1 { get; set; }
        public string MyProperty2 { get; set; }
    }
    

    Note: As an important note, keep in mind that such functionality is not useful for design-time at all. Because at design time, you need to show properties of the control in PropertyGrid in designer and you need to let the designer knows about those properties to be able to serialize values for them.