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?
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.