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

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

Rate This
  • Comments 5

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.

Attachment: ExpandableObjectConverterDemo.zip
Leave a Comment
  • Please add 3 and 2 and type the answer here:
  • Post
  • Thanks Jim. I was also following the particular forum question. It is good to understand this in detail

  • Thanks again for you answer and blogging this out!

  • What version of Visual Studio are you using?

    Your property grid has cool features that mine doesn't, like A-Z sorting.

    Is there a service pack I've missed?

    Cheers,

    Karl

  • No, you haven't missed a service pack, I accidentally used my machine (code in development) for the screen shots.  Sorry for the confusion.

  • I know this post is a little bit back, but I've a rather unusual problem apparently nobody can help me with.

    Situation: custom control with DP property of a custom class derived from DependencyObject with two DP properties. The first is of type CultureInfo, second one is of type System.Globalization.Calendar.

    When I create an instance of the DP property via property browser, I can edit the two sub properties in the property browser. The first DP property gets created as xaml attribute to the class, the second one (of type Calendar) not.

    I tried everything known to me to get the second property also as xaml attribute, but nothing works.

    I tried applying TypeConverter and ValueSerializer attribute.

    Is there a way to influence the automatic code generation of cider to force the xaml code generation of the second dp property as attribute?

    Thank you very much,

    Thomas.

Page 1 of 1 (5 items)