PropertyGrid.PropertyDefinitions should be bindable

Jan 26, 2012 at 1:29 PM
Edited Jan 26, 2012 at 2:46 PM

We wanted to have the PropertyDefinitions computed at run time (in the view model) so we used a binding like this:

 

                        
                        <Controls:ExtendedPropertyGrid x:Name="PropertyGrid"
                                                       Grid.Column="1"
                                                       DisplaySummary="True"
                                                       ShowSearchBox="False"
                                                       ShowSortOptions="False"
                                                       IsCategorized="True"
                                                       ShowAdvancedOptions="False"
                                                       SelectedObject="{Binding ActiveItem}"
                                                       AutoGenerateProperties="False"
                                                       PropertyDefinitions="{Binding ActiveItem.PropertyDefinitions}">

 

Unfortunally this didn't work due to a bug in PropertyGrid. Our work around at the moment is to use a derived class ExtendedPropertyGrid. It would be nice if this can be fixed in the original.

 

 

    public class ExtendedPropertyGrid : PropertyGrid
    {
        static ExtendedPropertyGrid()
        {
            // When the property definitions change also trigger recomputing of the property grid items
            PropertyDefinitionsProperty.OverrideMetadata(typeof(ExtendedPropertyGrid),
                new UIPropertyMetadata(null, OnPropertyDefinitionsChanged));
        }

        private static void OnPropertyDefinitionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var propertyGrid = d as ExtendedPropertyGrid;
            if (propertyGrid != null)
                propertyGrid.OnSelectedObjectChanged(propertyGrid.SelectedObject, propertyGrid.SelectedObject);
        }
    }
Jan 26, 2012 at 1:37 PM

Could you explain what the two bugs are so I can fix them?

Thanks

Jan 26, 2012 at 2:58 PM

Sorry it is only one bug, i corrected the post above.

Here is the definition of the DependencyProperty PropertyDefinitionsProperty:

        public static readonly DependencyProperty PropertyDefinitionsProperty = DependencyProperty.Register("PropertyDefinitions", typeof(PropertyDefinitionCollection), typeof(PropertyGrid), new UIPropertyMetadata(null));

There is no event triggered when the underlying value is changed, in contrast to SelectedObjectProperty.

So when you both dynamically bind SelectedObject and PropertyDefinitions the binding of SelectedObject will probably be resolved first (i.e. OnSelectedObjectChanged gets fired before PropertyDefinitions has been bound). When this happens OnSelectedObjectChanged will call GetObjectProperties which itself will use the current value of PropertyDefinitions to determine which properties to show. As the Binding of PropertyDefinitions hasn't been resolved yet it will be null so no items will be displayed in the grid.

My workaround fixed that with calling OnSelectedObjectChanged also when the PropertyDefinitions change.

I think you can reproduce the problem easily by having a ViewModel implement a property like:

        public PropertyDefinitionCollection PropertyDefinitions
        {
            get
            {
                return new PropertyDefinitionCollection
                       {
                           new PropertyDefinition {Name = "Name"},
                           new PropertyDefinition {Name = "Description"},
                           new PropertyDefinition {Name = "Value"},
                       };
            }
        }
and bind to it like in the example above.