How to: Sub-property editing in the Visual Studio 2008 WPF Designer Property Browser

Recently I saw a post on the forums asking about how to get subproperties to show up in the Property Browser for WPF projects.  This inspired me to blog about it as I'm sure other people are also running into this question.

What do I mean by sub-properties?  Consider the following screen shot of the Property Browser:

Notice how to the left of the ExpandablePersonObject property there is a square with a '-' in it?  That is the expanded state for sub-properties.  When collapsed, it will show up as a '+'.

The sub-properties are the Age, Name and ShirtColor that are properties on the ExpandablePersonObject type (shares the same name as the property).

So the question is: how do I create a property for a type that shows my sub-properties?

The short answer is that the property or the type of the property needs to have the ExpandableObjectConverter TypeConverter applied to it.  That said, in order to fully answer that question, I created a project that illustrates the various scenarios (see attached zip to this post). 

There are two interesting cases, the first is for DependencyObject derived types and the second is for System.Object derived types.

In the case of DependencyObjects, you pretty much get the behavior for free because Cider itself adds the ExpandableObjectConverter to DependencyObjects (note: Blend has the same behavior as Cider for all this stuff, we designed it all together).

So, if I have a type such as this:

    public class PersonDependencyObject : DependencyObject
    {
        public static readonly DependencyProperty AgeProperty = DependencyProperty.Register("Age", typeof(int), typeof(PersonDependencyObject));

        public int Age
        {
            get { return (int)GetValue(AgeProperty); }
            set { SetValue(AgeProperty, value); }
        }

(. . .)

and the property on the control that will be selected in the designer is:

         public PersonDependencyObject PersonDependencyObject;

The Age, ShirtColor and Name properties on the PersonDependencyObject type will be shown in the Property Browser.

If the type of the property is derived from object:

    public class PersonObject
    {
        private string _Name = "";
        private int _Age = 0;
        private Brush _ShirtColor = Brushes.Blue;

        public string Name
        {
            get { return _Name; }
            set { _Name = value; }
        }
(. . .)

You have a little more work to do.

You can either set the TypeConverter on the type itself:

    [TypeConverter(typeof(ExpandableObjectConverter))]
    public class ExpandablePersonObject (. . .)

or on the property on the control:

        [TypeConverter(typeof(ExpandableObjectConverter))]
        public PersonObject PersonObjectWithExpansion

If you do either of these, you will get the sub-properties showing up for that property.

You will notice one other thing here, in order for sub-properties to show up, you need to ensure that the property is editable in XAML.  That is, if you programmatically set an instance on the property or set an instance as the default property, you'll get the + to expand/collapse but the subproperties will not show up underneath. 

For example if I were to programmatically set my property to an instance:

         public PersonControl()
        {
            InitializeComponent();
            PersonDependencyObject = new PersonDependencyObject();
        }

Looking at the Property Browser:

Notice how you get the expander that shows the subproperties expanded but you cannot see or edit them.  This is because the property is not set in XAML.  We want to improve this experience in a future release however this is what we are stuck with for now.

For properties that do not have a value, if you click the dropdown and select the type in the drop down, that will create a new instance in the XAML  For example, if in my attached sample I select the "PersonObject" type in the drop down for the PersonObjectWithExpansion property, I will get the following added to the XAML:

        <local:PersonControl>
            <local:PersonControl.PersonObjectWithExpansion>
                <local:PersonObject Age="0" Name="" ShirtColor="Blue" />
            </local:PersonControl.PersonObjectWithExpansion>
        </local:PersonControl>

The sub-properties will be expanded and you can edit them using the property browser.

You might now ask if there is a way to customize that drop down of types...  the answer is yes!  There is.  For this you will have to use the Metadata Store to add the attribute and the attribute is the NewItemTypesAttribute.  When you decorate a property with the NewItemTypesAttribute, you specify the list of types that are compatible to be instantiated and set as the property value for the given property -- i.e. it shows up in the drop down.

ExpandableObjectConverterDemo.zip