property grid image

PropertyGrid is a control for editing the property values of a compound object. There are no restrictions on the type of the object. You will find a sample project demonstrating the features of PropertyGrid in the Samples\PropertyGrid folder.

Using PropertyGrid in its default configuration is as simple as setting a value for SelectedObject, like so:

<ctrls:PropertyGrid SelectedObject="{StaticResource ObjectToBeEdited}" />

The basic design is as follows: PropertyGrid inherits from Control. The properties are viewed via a contained PropertyGridItemsControl which inherits from ItemsControl (and which is accessible via PropertyGrid.PropertyItemsControl.) The control which serves as container for property items and provides the view of the properties is PropertyGridItem. By default, the selected object’s properties are obtained from a call to System.ComponentModel.TypeDescriptor.GetProperties(), which returns a collection of PropertyDescriptors. Each PropertyDescriptor is wrapped by an instance of PropertyGridProperty, which in turn is added to the Items collection of the PropertyGridItemsControl.

PropertyGridItem inherits from HeaderedItemsControl (because it needs to display possible sub properties.) The Header property is used to display property’s Display Name. (HeaderTemplate can be modified to change the default look.) Each PropertyGridItem contains a PropertyGridEditor for editing the property’s value. A reference to the editor is available through property PropertyGridItem.Editor. A lot of flexibility is provided by the default Template of PropertyGridEditor, with even more flexibility available through PropertyGridItem.EditorStyle.

PropertyGrid has three settings which affect which properties are included on a global basis: ShowAttachedDependencyProperties, ShowReadOnlyProperties and ShowSubProperties. Each of these can be overridden on a per-property, per-category, per-property type or per-selected object type via an instance of PropertyDefinition added to PropertyGrid.PropertyDefinitions collection. Property definitions can also be used to override a property’s category, display name, sort order, description and more.

A set of editors for common types is built-in to the property grid. There is of course the string editor, which is the default editor for all properties. There is a numeric editor complete with spinner, a Boolean editor, an editor for enumerated types, Color and Brush editors, an editor for collections of primitive types and finally an editor for collections of class types. Each built-in editors has a set of options exposed by a dedicated instance of EditorDescriptor. The default editor descriptors are available via property PropertyGrid.DefaultEditorDescriptors. Customized editor descriptors can also be applied via a PropertyDescriptor or as a custom Attribute on the property declaration. In addition to the built-in editors, completely new editors can be defined on a per-property type or per-property name basis.

More about property and editor customization is provided below, along with much more.

Public Interface

PropertyGrid Interface

PropertyGrid Properties

CLR Properties

Properties – Gets a reference to the collection of PropertyGridProperty items currently being displayed.

DefaultEditorDescriptors – Get a reference to the set of default EditorDescriptors. These can be modified at run-time, before properties are loaded. More about editor descriptors and customizing property editors is provided below.

PropertyDefinitions – Get a reference to the set of custom property definitions which are used to customize various aspects of property views. By default this is an empty set. It can be modified by client either directly or by setting a value for CustomPropertyDefinitions. More about property definitions and customizing properties is provided below.

ToolBarItems – Get a reference to the list of objects which are used to populate the ToolBar. This is an ObservableCollection so it can be modified at run-time.

MaxSubPropertyLevel – Get or set the maximum depth of sub-properties to display, when sub-properties are being displayed. By default, this has an arbitrary value of 8 which is used to guard against infinite recursion.

Dependency Properties

BrowsableAttributes – Get or set an optional collection of Attributes to use as filter when loading available properties for the property grid. Please see MSDN documentation for TypeDescriptor.GetProperties method for more information. If unset, then by default properties which have no BrowsableAttribute or BrowsableAttribute.Yes are included.

CustomPropertyDefinitions – Get or set an optional list of custom property definitions, which allow customization of a property’s category, sort order, display name and many more. More about custom property definitions is provided below.

ErrorNotification – specifies how errors in editor validation are communicated to the end user. Possible values are None, MessageBox and ValidationTemplate. More about property validation is provided below.

ExpanderAlignment – Get or set whether the expander buttons for property sub items are aligned in a single column along the left margin of the property grid or are indented according to the property’s level in the sub property hierarchy. Will have no effect if ShowSubProperties is false.

Filter – Get or set a string to use for filtering properties. If a property’s display name contains the filter string, then the property will be displayed in the property grid.

IgnoredCategories – Set a list of names of categories to ignore. If a property’s category is in the list, then that property will not be displayed by the property grid.

IgnoredProperties – Set a list of names of properties to ignore. If a property’s name is in the list, then that property will not be displayed by the property grid.

InnerLeftMargin – Get or set the width of the left margin of the property grid. The left margin is the space between the property grid’s left edge and where the property names are rendered and that provides the space for category and sub property expander buttons.

IsSelectionFocusAware – Get or set whether the selected property highlight color should be modified when the property grid does not contain the keyboard focus. Default value is true.

PropertyValidator – Get or set an instance of IPropertyGridPropertyValidator which is used for property validation. See below for more about property validation.

SelectedObject – Get or set the object who’s properties are being edited.

SelectedObjects – Get or set a list of objects who’s properties are to be edited simultaneously. Only those properties which are common to all objects in the list are displayed.

SelectedProperty – Get or set the currently selected or active property.

ShowAdvancedPropertiesButton – Get or set whether to show the built-in advanced properties button. The advanced properties button, when clicked, raises the routed event PropertyGridItem.AdvancedPropertiesButtonClick which the client must handle to show a dialog or other desired effect.

ShowAttachedDependencyProperties – Get or set whether to include attached dependency properties that are deemed applicable by the method TypeDescriptor.GetProperties(). Note that this setting can be overridden on a per-property basis using property definitions (more below.) The default value is false.

ShowCategories – Get or set whether properties are grouped by category. The default value is true.

ShowHelpPanel – Get or set whether the help panel (displayed at bottom of property grid by default) is shown.

ShowReadOnlyProperties – Get or set whether read-only properties are included. Default value is false. Note that this setting can be overridden on a per-property basis using a property definition.

ShowSearchBox – Get or set whether the search box is shown. Default is false.

ShowSubProperties – Get or set whether property sub properties are shown. Default value is true. Note that this setting can be overridden on a per-property basis using with custom property definition.

ShowToolTips – Get or set whether the default tool tips are shown. Default value is true.

ShowToolBar – Get or set whether the tool bar is visible. Default value is true.

UseBuiltInContextMenu – Get or set whether the built-in context menu is available. Built-in context menu includes a property Reset command. There is an example of how to intercept the context menu opening and customize it to your needs. The example is in CustomizingSample of PropertyGridSample.

VisualStyle – Get or set the visual style of the property grid. Possible values are Default, WindowsExplorer, Office2010Blue, Office2010Silver, Office2010Black and VisualStudio2010. Important: Setting visual style via this property will not change styles of other controls in the application. To achieve consistent look-and-feel throughout the application, use VisualStyleManager.VisualStyle attached property on the root element.

PropertyGrid Methods

FindContainer(PropertyGridProperty) – Recursively search for the PropertyGridItem which provides the view of the specified property.

GetPropertyGridItems() – Returns an enumeration of the PropertyGridItem controls which are the containers for the properties currently being shown.

PropertyGrid Events

SelectedObjectChanged – A bubbling routed event raised when the value of SelectedObject changes.

SelectedObjectsChanged – A bubbling routed event raised when the value of SelectedObjects changes or when the the collection change.

PropertyGridItem Interface

PropertyGridItem Properties

CLR Properties:

ParentPropertyGrid – Get a reference to the parent PropertyGrid.

ParentPropertyGridItem – Get a reference to the parent PropertyGridItem, if current property is a sub property of another property.

Property – Get a reference to the PropertyGridProperty which wraps the PropertyDescriptor being viewed. This is the same object as DataContext.

Editor – Get a reference to the PropertyGridEditor instance.

Dependency Properties:

AdvancedPropertiesButtonCommand – Get or set a command to execute when the advanced properties button is clicked.

CellPadding – Get or set the amount of padding for both Header and Editor.

EditorStyle – Get or set a custom style to apply to the contained instance of PropertyGridEditor.

HeaderReadOnlyTemplate – Get or set a DataTemplate to use for displaying the Header (i.e. the property’s name) when the property is read only.

IsExpanded – Get or set whether the property’s sub properties are displayed in sub-tree. Has no effect if sub properties are not being shown or if the property has no sub properties.

IsSelectable – Get or set whether the property can be selected.

IsSelectable – Get or set whether the property is currently selected.

ShowAdvancedPropertiesButton – Get or set whether the advanced properties button is displayed. By default this property takes its value from the parent PropertyGrid’s property of the same name.

PropertyGridItem Methods

FindContainer(PropertyGridProperty) – Recursively search for the PropertyGridItem which provides the view of the specified property.

PropertyGridItem Events

Selected – A bubbling routed event raised when the value of IsSelected changes to true.

Unselected – A bubbling routed event raised when the value of IsSelected changes to false.

AdvancedPropertiesButtonClick – A bubbling routed event raised when the advanced properties button is clicked.

PropertyGridEditor Interface

PropertyGridEditor Properties

CLR Properties

Property – Get a reference to the PropertyGridProperty representing the property being edited. (Same object as DataContext.)

AlwaysShowInCellTemplate – Get or set whether the InCellTemplate is shown even in the case where a drop down is being used and IsInCellEditingEnabled is false (in which case the default behavior is to display the value in the drop down button itself, like a non-editable ComboBox.)

Dependency Properties

ErrorNotification – Get or set the method that errors are reported to the end user. Possible values are None, MessageBox or ErrorTemplate. By default, this property gets its value from the parent PropertyGrid’s property of the same name.

ClickMode – Get or set the ClickMode (Press or Release) of the button which shows the drop down, if the drop down is used for the current instance.

DialogWindowType – Get or set the Type for dialog window. When property IsDialogWindowOpen is set to true, a new instance of type DialogWindowType is created and shown via call to Window.ShowDialog(). Note that the dialog window type must derive from System.Windows.Window. If DialogWindowType is set to a non-null value, and no drop down or in row templates are set, then editor will show the toggle button which when checked will cause IsDialogWindowOpen to be set to true.

DropDownClosesOnClick – Get or set whether the drop down closes automatically when a click event or mouse left button up event fires from within the drop down content. (The drop down always closes with a click event that originates outside of the drop down content.) The default value is false.

DropDownTemplate – Get or set a ControlTemplate to apply to the ContentControl which is used to display drop down content. The content of the drop down is PropertyGridEditor.Value. By default, when this property to a non-null value, the editor displays a toggle button which opens and closes the drop down.

InCellTemplate – Get or set a ControlTemplate to apply to the ContentControl which presents the property value as a string, appearing in the property’s Value cell (second column.) Its content is set to PropertyGridEditor.ValueString. The default InCellTemplate contains a TextBox.

InRowTemplate – Get or set a ControlTemplate used as Template for the ContentControl which displays the editor in what is essentially a new row immediately below the property being edited. By default, if this property is set to a non-null value, the editor displays a toggle button which toggles the visibility of the in cell content. If both InRowTemplate and DropDownTemplate are set, then the toggle button is three-state.

InRowRelativePosition – Get or set a value which determines where in relation to the property being edited the in row content should be located. Possible values are BelowProperty and CategoryEnd. In the first case the editor is displayed directly below the property being edited. In the second, the editor is displayed as the last row in the category of the property being edited (applies only if PropertyGrid.ShowCategories is set to true.)

IsDialogWindowOpen – Get or set whether the dialog window is open. Setting to true when there is no value for DialogWindowType will have no effect.

IsInCellEditingEnabled – Get or set whether the Value should be editable directly in the cell TextBox. If false, the text box is made read only. If true, then the TextBox is editable. Default value is true.

IsDropDownOpen – Gets whether the drop down is open. This is a read-only dependency property.

IsInRowContentVisible – Gets whether the in row content is visible. This is a read-only dependency property.

Value – Get or set the value of the underlying property. A binding is created between this property and the Value property of the PropertyGridProperty which wraps the actual property being edited. The binding’s update source trigger is Explicit and in practice source is generally updated when the editor loses focus.

ValueString – Get or set the value of the underlying property. Like property Value, ValueString is bound to the Value property of the PropertyGridProperty which wraps the actual property being edited. The difference is that the binding for ValueString uses a value converter for converting from the property’s native Type to String and back. The value converter uses the property’s TypeConverter for this purpose.

PropertyGridEditor Methods

CommitPendingChanges() – Causes all pending changes to be committed to the underlying property.

ClearPendingChanges() – Clears all pending changes from the buffer.

PropertyGridEditor Events

PropertyValueChanged – A bubbling routed event raised after pending changes have been committed (written) to the underlying property.

PropertyValueChanging – A bubbling routed event raised before pending changes are committed to the underlying property. Set the Handled property of the event arguments to true to prevent the changes from being committed.

EditEscaped – A bubbling routed event raised when an edit operation is terminated, such as when the escape key is pressed.

Representing Properties: PropertyGridProperty

The properties of the SelectedObject that are included in the veiw are represented, or wrapped, by instances of PropertyGridProperty. PropertyGridProperty is essentially a ViewModel where the actual properties are the Model (And PropertyGridItem is the View). The properties of the current SelectedObject are stored and managed by the property grid’s Properties collection, a collection of type PropertyGridPropertyCollection which derives from ObservableCollection<PropertyGridProperty>.  When property grid’s SelectedObject is set or changes, PropertyGridPropertyCollection reloads itself with the properties of the new selected object. This takes place in response to event PropertyGrid.SelectedObjectChanged (or PropertyGrid.SelectedObjectsChanged.) After the properties are fully loaded, PropertyGridPropertyCollection raises event TargetChanged.

One way to customize properties in code is with an event handler for PropertyGridPropertyCollection.TargetChanged. Individual properties can be accessed by property name via the string indexer. An enumeration of all properties of a given Type is available via the Type based indexer.

To create a totally custom property, simply create a new instance of PropertyGridProperty (or a derivative) set the property values as desired and add to the property grid’s Properties collection.

PropertyGridProperty exposes the following publically available properties:

  • AllowReset – Get or set whether the Reset command should be enabled. By default, this value is false for read-only properties and true for all others.
  • CategorySortString – Get or set the string used to sort the property’s category. By default this is equal to Category.
  • EditorDescriptor – Get or set a custom EditorDescriptor to use for the property’s editor. More about editor descriptors is provided below.
  • HierarchyLevel – Gets the level in the property hierarchy of the current property.
  • IsSelected – Get or set whether the property is currently the selected property in the property grid.
  • IsSubProperty – Returns true if the current property is a sub property.
  • ParentCollection – Gets the PropertyGridPropertyCollection which is the immediate container for the current property.
  • ResetCommand – Get or set an ICommand used by UI elements for the purpose of resetting the property value. By default this is a command which when executed calls method Reset().
  • RootProperty – Gets the property which is at the root of the current property. Applicable if the property is a sub property.
  • Show – Get or set whether to show this property in the display.
  • ShowSubProperties – overrides any other settings which affect whether sub properties are shown, including PropertyGrid.ShowSubProperties and PropertyDefinition.ShowSubProeprtiesOverride.
  • SortString – Get or set the string used to sort the property. By default this is equal to Name.
  • Target – Gets the object which owns the property. (The property is a member of Target.)
  • Targets – Gets the collection of objects each of which own a property of same description. (Used when the property is in multi-select mode.)
  • Validator – Get or set a custom object used for validation of the property value when set. More about property validation is provided below.
  • ValidationCallback – Get or set a delegate of type Func<PropertyGridProperty, string> which is invoked prior to a new Value being committed to the underlying property. The delegate should return a string providing description of error if the proposed Value (as obtained via PropertyGridProperty.Value) is invalid.

The following properties take their value directly from the underlying PropertyDescriptor:

  • Category – Get or set the category for the property. By default this value is obtained from the underlying PropertyDescriptor.
  • Description – Get or set the description.
  • DisplayName – Get or set the display name for the property. By default this value is obtained from the underlying PropertyDescriptor.
  • IsReadOnly – Get or set whether the property should be considered as read-only by the editor. By default this value is obtained from the underlying PropertyDescriptor.
  • Name – Get or set the property’s Name.
  • PropertyType – Get or set the Type of the property.
  • SubProperties – Gets or sets the PropertyGridPropertyCollection containing the sub properties of the current property. Will be null if there are no sub properties.
  • TypeConverter – Get or set a TypeConverter for the property’s value.
  • Value – Get or set the property’s value.

Customizing Properties: PropertyDefinition

PropertyDefinition provides the means by which PropertyGridProperty instances can be customized in Xaml. A PropertyDefinition exposes properties which allow for overriding the effective property values of their targeted properties. PropertyDefinition instances are added to the control’s environment via the read-only property PropertyGrid.PropertyDefinitions. PropertyDefinitions returns a reference to a PropertyDefinitionCollection, which is simply an ObservableCollection of PropertyDefinition. There are two ways to add property definitions to the global property definition collection. One is by adding the definitions directly to the collection, and the other is by setting a value for CustomPropertyDefinitions. (Both can be done in either in Xaml or in code.) CustomPropertyDefinitions is a dependency property and it provided to enable binding in for example an MVVM type scenario.

There are two items of information which are required for any PropertyDefinition. The first is specification of what property the definition is targeting and the second is the specific property (or properties) of the property that are being overridden. A single property definition can target a single property (via property name) or a set of properties (via category or property type.) Note that a property definition with no restriction on the target property will be applied to all properties. Property definitions are additive. That is, it is possible to define multiple property definitions targeting the same property. In case of a conflict, the last definition added to the collection wins.

Here is a list of the properties which are used to specify the target property or properties:

  • PropertyGridPropertyType – the property definition will be applied where the PropertyGridProperty instance is an override of PropertyGridProperty of the specified type. Used for custom defined properties.
  • SelectedObjectType – use to restrict the definition so that it will be applied only when the property grid’s SelectedObject is of the specified Type.
  • TargetCategory – the property definition will be applied to all properties of the specified category.
  • TargetPropertyName – the property definition will be applied to the property of the spevified Name.
  • TargetPropertyType – the property definition will be applied to all properties which are of the specified Type.
  • TargetPropertyOwnerType – provided specifically for dependency properties. The property definition will be applied to all properties which are dependency properties who’s owner is of the specified type. Intended to enable customization of the attached dependency properties that are displayed.

Here is the list of PropertyDefinition properties which are used to change the property’s display attributes:

  • AllowResetOverride – Overrides the current value of PropertyGridProperty.AllowReset.
  • CategoryOverride – Overrides the current value of PropertyGridProperty.Category.
  • CategorySortStringOverride – Overrides the current value of PropertyGridProperty.CategorySortString.
  • DescriptionOverride – Overrides the current value of PropertyGridProperty.Description.
  • DisplayNameOverride – Overrides the current value of PropertyGridProperty.DisplayName.
  • EditorDescriptorOverride – Overrides the editor descriptor used for the property’s editor.
  • EditorStyle – Sets the style for the property’s editor.
  • MaxSubPropertyLevelOverride – Overrides the value of MaxSubPropertyLevel set on the parent property grid.
  • PropertyGridItemStyle – Sets the Style for the containing PropertyGridItem control of the target property.
  • ShowPropertyOverride – Overrides the current value of PropertyGridProperty.Show.
  • ShowSubPropertiesOverride – Overrides the current value of PropertyGridProperty.ShowSubProperties.
  • TypeConverterOverride – Overrides the current value of PropertyGridProperty.TypeConverter.
  • ValidationErrorTemplate – Sets the ControlTemplate used for validation error display when editing a value.

There are extensive examples of the use of PropertyDefinition in the sample PropertyGridSample that is provided with the installation. For example of use in Xaml, see the Page CustomizeSamplePage. For example of use in code, see CodeBasedSamplePage. Here is an example of how to add PropertyDefinition to the property grid in xaml:

<ctrls:PropertyGrid>            
    <ctrls:PropertyGrid.PropertyDefinitions>
        <!-- Defining custom editors for Thickness values, Styles, ContolTemlate, DataTemplate. -->
        <ctrls:PropertyDefinition TargetPropertyType="{x:Type Thickness}" EditorStyle="{StaticResource CustomThicknessEditor}" />
        <!-- Changes name of category 'Misc' to 'Other' -->
        <ctrls:PropertyDefinition TargetCategory="Misc" CategoryOverride="Other" />
        <!-- These are being moved into 'Other' category. -->
        <ctrls:PropertyDefinition TargetPropertyName="ContentTemplate" CategoryOverride="Other" />
        <ctrls:PropertyDefinition TargetPropertyName="ContentStringFormat" CategoryOverride="Other" />
    </ctrls:PropertyGrid.PropertyDefinitions>            
</ctrls:PropertyGrid>

And here is an example in code:

PropertyGrid.PropertyDefinitions.Add(
    new PropertyDefinition { TargetCategory = &quot;Misc&quot;, CategoryOverride = &quot;Common&quot; });

Customizing the Editor

Editing in PropertyGrid is managed by the control PropertyGridEditor. By default, PropertyGridItem (the container type for PropertyGridProperty) has in its Template an instance of PropertyGridEditor positioned in what is essentially the second column. The job of PropertyGridEditor is both to display the property value and to serve as its editor.

One way to customize the editor for a given property is to define a custom Style targeting PropertyGridEditor and set it as the value for PropertyGridItem.EditorStyle, which can be accomplished via a PropertyDefinition (See above.) There is essentially no limit as to the sort of editor which can be created via a custom editor Style.

The other way to customize the editor for a given property is through an EditorDescriptor.

Editor Descriptor

The main purpose of EditorDescriptor is to serve as a means of providing options to the set of built-in editors. However, custom editor descriptors can be used as well for more advanced customization scenarios, such as setting the editor Style or other options at run-time based on factors known only at run-time, or defining a custom value converter for converting between a property’s true value and its string representation.

Note: the default data context for a PropertyGridEditor contained by a PropertyGridItem is the PropertyGridProperty which the item is the container for. Therefore, Bindings defined within the PropertyGridEditor Template, or its DropDownTemplate, InRowTemplate or InCellTemplate, can access the associated EditorTemplate through the EditorDescriptor property of PropertyGridProperty. For example: ItemsSource={Binding EditorDescriptor.PossibleValues}

The base editor descriptor class has the following virtual properties and methods:

  • ToStringValueConverter – This property returns an IValueConverter which is used in the Binding for the editor’s ValueString property, which is described above. By default, this returns a statically defined instance of PropertyToStringValueConverter. PropertyToStringValueConverter makes use of the property’s TypeConverter, if one is defined, to convert to and from a string based representation of the property’s value and its true value.
  • EnableInCellEditing – Boolean property. Maps directly to PropertyGridEditor.IsInCellEditingEnabled.
  • StringFormat – This property defines an optional string format which may be applied to the editor’s display value.
  • GetEditorStyle(PropertyGridItem) – This method is called from within PropertyGridItem‘s OnApplyTemplate() to set a value for property EditorStyle. Note that if the PropertyGridItem has a non-null value for EditorStyle at the time that its template has loaded, then EditorDescriptor.GetEditorStyle(…) is not called.
  • PrepareEditor(PropertyGridEditor) – This method is called immediately after GetEditorStyle(…) and provides an opportunity to set properties on the editor at run time.

A custom editor descriptor can be assigned to a property directly in code via PropertyGridProperty.EditorDescriptor, or via a PropertyDefinition (see above.)

Alternatively, note that EditorDescriptor inherits from System.Attribute. This makes it possible to assign an editor descriptor to a property when the property itself is defined. Of course, to take advantage of this, it is necessary to own the code which defines the property…

Default Editors

If a property does not have a value for EditorDescriptor set at the time it is called for, a default editor descriptor is assigned. The default editor descriptor maps to the default editor for the property type. Default editor descriptors are provided by an instance of EditorDescriptorSet which is the value of the property grid’s DefaultEditorDescriptors property. Note that this property is given a default value, but it is a read/write property, meaning that you can override EditorDescriptorSet to provide custom default behavior.

EditorDescriptorSet has a single virtual method: GetEditorForType(Type) which returns the EditorDescriptor most appropriate for the property type, by default. The default implementation returns the following based on the given property type:

  • if property type == Boolean: returns BooleanEditorDescriptor.
  • if property type is Enum: EnumEditorDescriptor.
  • if property type is System.Windows.Media.Color: ColorEditorDescriptor.
  • if proeprty type is System.Windows.Media.Brush: BrushEditorDescriptor.
  • if property type is FontStyle, FontWeight, FontStretch: SelectorEditorDescriptor.
  • if property type is ICollection:
    • if collection member type is string or primative: PrimitiveCollectionEditorDescriptor.
    • otherwise: CollectionEditorDescriptor.
  • all others: EditorDescriptor.

The default editor descriptor for any of the above can be modified by adding an instance of the appropriate type to the property grid’s editor descriptor set. For example, the default implementation of BooleanEditorDescriptor has a value of InLineCheckBox for its Type property. To change this for all occasions where the default Boolean editor is used, add a modified version of BooleanEditorDescriptor to the collection as such:

<ctrls:PropertyGrid SelectedObject="{Binding ElementName=ObjectListBox, Path=SelectedItem}">
    <ctrls:PropertyGrid.DefaultEditorDescriptors>
        <!-- Changes the default boolean editor from using a CheckBox to a Yes/No drop down. -->
        <ctrls:BooleanEditorDescriptor EnableInCellEditing="False" Type="DropDown"  DisplayNameFalse="No" DisplayNameTrue="Yes" />
    </ctrls:PropertyGrid.DefaultEditorDescriptors>
</ctrls:PropertyGrid>

Built-In Editors

The following built-in editors are included with PropertyGrid:  a Boolean editor, a Brush editor, a Collection editor, a Color editor, an generic editor for enumerated types, an editor for numeric types, an editor for  collections of primitive types and strings, an editor for selecting from a set of possible values and the default editor. Some of these editors are used as default editors for the appropriate property Type. Others are opt-in editors, meaning that it is necessary to assign the corresponding editor descriptor to the property.

Each of the built-in editors has a set of options, in addition to the set of properties available on the base class EditorDescriptor which are described above. The editor descriptor Type, ComponentResourceKey identifying the editor style and the options that are available for the built-in editors are described below:

The Boolean Editor

Provides an editor for properties of type Boolean.

Editor descriptor: BooleanEditorDescriptor.

Editor Style resource key: PropertyGridEditor.DefaultBooleanEditorStyleKey.

Properties:

  • AutoComplete – An enumeration with Flags attribute. Applies only when Type == DropDown. Possible values are:
    • Off – No auto complete.
    • ReadOnly – Auto complete is enabled. User cannot enter values which are not in the list of possible values.
    • FreeText – Auto complete is enabled and user can enter any value.
    • DontConvertCase – When auto complete is enabled, suggestions are case sensitive.
  • DisplayNameTrue – Determines the display name for a value of True. Applies only when Type == DropDown.
  • DisplayNameFalse – Determines the display name for a value of False. Applies only when Type == DropDown.
  • EnableInCellEditing – Default value is true. Applies only when Type == DropDown. Inherited from EditorDescriptor.
  • FormatString – Default value is null. Inherited from EditorDescriptor.
  • Type – An enum, possible values are:
    • InLineCheckBox – (Default) the value is determined by a check box set inline with the value cell. 
    • DropDown – The possible values are presented in a drop down.

Examples:

[BooleanEditorDescriptor(Type = BooleanEditorDescriptor.EditorType.DropDown, EnableInCellEditing = false, DisplayNameFalse = "Definitely Not", DisplayNameTrue = "Yes, for Sure")]
public bool CustomBoolValue { get; set; }
<ctrls:PropertyDefinition SelectedObjectType="{x:Type TextBox}" TargetPropertyType="{x:Type sys:Boolean}">
    <ctrls:PropertyDefinition.EditorDescriptorOverride>
        <ctrls:BooleanEditorDescriptor AutoComplete="ReadOnly" EnableInCellEditing="True" DisplayNameTrue="Definitely, Yes" DisplayNameFalse="Absolutely Not" />
    </ctrls:PropertyDefinition.EditorDescriptorOverride>
</ctrls:PropertyDefinition>

The Brush Editor

Provides an editor for properties of type System.Windows.Media.Brush.

Editor descriptor: BrushEditorDescriptor.

Editor Style resource key: PropertyGridEditor.DefaultBrushEditorStyleKey.

Properties:

  • EnableInCellEditing. Default value is true. Inherited from EditorDescriptor.
  • FormatString – Default value is null. Inherited from EditorDescriptor.
  • Type – An enum. Possible values are:
    • DropDown – Editor is presented in a drop down only.
    • InRow – Editor is presented in a row below the property being edited, only.
    • ThreeState – Editor is both drop down and in row.
    • InCategory – Editor is presented as last row in property’s category.

Examples:

[BrushEditorDescriptor(Type=BrushEditorDescriptor.EditorType.InCategory)]
public Brush BrushValue { get; set; }
<ctrls:PropertyDefinition TargetPropertyType="{x:Type Brush}" CategoryOverride="Brushes">
    <ctrls:PropertyDefinition.EditorDescriptorOverride>
        <ctrls:BrushEditorDescriptor EnableInCellEditing="True" Type="InCategory" />
    </ctrls:PropertyDefinition.EditorDescriptorOverride>
</ctrls:PropertyDefinition>

The Collection Editor

Provides an editor for properties whose Type implements ICollection and where the collection member type is a class.

Editor descriptor: CollectionEditorDescriptor. Inherited from EditorDescriptor.

Editor Style resource key: PropertyGridEditor.DefaultCollectionEditorStyleKey.

Properties:

  • EnableInCellEditing. Default value is false. Inherited from EditorDescriptor.
  • FormatString – Default value is null. Inherited from EditorDescriptor.
  • Text – Defines a custom string to be displayed in the property’s value cell.
  • NewItemTypes – An optional list of Types to be included in the collection editor’s create new item drop down.

Examples:

[CollectionEditorDescriptor(typeof(SolidColorBrush), typeof(LinearGradientBrush), typeof(RadialGradientBrush), typeof(ImageBrush), Text = "(Brushes)")]
        public List<brush> CollectionOfBrushes { get; set; }
<ctrls:PropertyDefinition TargetPropertyName="BrushCollection">
    <ctrls:PropertyDefinition.EditorDescriptorOverride>
        <ctrls:CollectionEditorDescriptor  Text="(Brushes)">
            <ctrls:CollectionEditorDescriptor.NewItemTypes>
                <x:Type TypeName="SolidColorBrush" />
                <x:Type TypeName="LinearGradientBrush" />
                <x:Type TypeName="RadialGradientBrush" />
            </ctrls:CollectionEditorDescriptor.NewItemTypes>
        </ctrls:CollectionEditorDescriptor>
    </ctrls:PropertyDefinition.EditorDescriptorOverride>
</ctrls:PropertyDefinition>

The Color Editor

Provides an editor for properties of type System.Windows.Media.Color.

Editor descriptor: ColorEditorDescriptor.

Editor style resource key: PropertyGridEditor.DefaultColorEditorStyleKey.

Properties:

  • EnableInCellEditing. Default value is true. Inherited from EditorDescriptor.
  • FormatString – Default value is null. Inherited from EditorDescriptor.
  • Type – An enum. Possible values are:
    • DropDown – Editor is presented in a drop down only.
    • InRow – Editor is presented in a row below the property being edited, only.
    • ThreeState – Editor is both drop down and in row.
    • InCategory – Editor is presented as last row in property’s category.

Examples:

[ColorEditorDescriptor(Type = ColorEditorDescriptor.EditorType.InRow)]
public Color ColorValue { get; set; }
<ctrls:PropertyDefinition TargetPropertyType="{x:Type Color}">
    <ctrls:PropertyDefinition.EditorDescriptorOverride>
        <ctrls:ColorEditorDescriptor EnableInCellEditing="True" Type="InRow" />
    </ctrls:PropertyDefinition.EditorDescriptorOverride>
</ctrls:PropertyDefinition>

The Enum Editor

Provides an editor for enumerated types. It automatically populates its set of possible values from the Type of the enumeration.

Editor descriptor: EnumEditorDescriptor.

Editor style resource key: PropertyGridEditor.DefaultEnumEditorStyleKey.

Properties:

  • AutoComplete – An enumeration with Flags attribute. Applies only when Type == DropDown. Possible values are:
    • Off – No auto complete.
    • ReadOnly – Auto complete is enabled. User cannot enter values which are not in the list of possible values.
    • FreeText – Auto complete is enabled and user can enter any value.
    • DontConvertCase – When auto complete is enabled, suggestions are case sensitive.
  • DisplayNames – Defines a list of custom display names for the enum values. If null, then the default enum names are used.
  • EnableInCellEditing. Default value is false. Inherited from EditorDescriptor.
  • FormatString – Default value is null. Inherited from EditorDescriptor.
  • Type – An enum. Possible values are:
    • DropDown – (Default) the enum values are presented in a drop down.
    • InLine – the enum values are presented directly in the value cell, using radio buttons or check boxes to select by.

Examples:

[EnumEditorDescriptor("Can See", "Invisible", "Just not there", Type = EnumEditorDescriptor.EditorType.InLine)]
public Visibility VisibilityValue { get; set; }
<ctrls:PropertyDefinition TargetPropertyType="{x:Type Visibility}">
    <ctrls:PropertyDefinition.EditorDescriptorOverride>
        <ctrls:EnumEditorDescriptor Type="InLine">
            <ctrls:EnumEditorDescriptor.DisplayNames>
                <sys:String>Can See</sys:String>
                <sys:String>Invisible</sys:String>
                <sys:String>Just not there</sys:String>
            </ctrls:EnumEditorDescriptor.DisplayNames>
        </ctrls:EnumEditorDescriptor>
    </ctrls:PropertyDefinition.EditorDescriptorOverride>
</ctrls:PropertyDefinition>

The Numeric Editor

Provides an editor for numerical values that includes "spinner" buttons for incrementing and decrementing a the value. Note that by default this editor is not used for numerical values. It is necessary to apply an instance of the editor descriptor (NumericEditorDescriptor) to the desired property for this editor to be used.

Editor descriptor: NumericEditorDescriptor.

Editor style resource key: PropertyGridEditor.DefaultNumericEditorStyleKey.

Properties:

  • DecreaseCommand – Sets the command which is executed by the decrease repeat button click event. While it is possible to set a custom command, a default command is provided which will work in most scenarios.
  • EnforceMinMax – Determines whether a validation rule should be applied to the property which enforces the Min and Max values. Applies only if EnableInCellEditing is true. Default value is true.
  • EnableInCellEditing. Default value is true. Inherited from EditorDescriptor.
  • FormatString – Default value is "F" + Precision when Precision is greater than or equal to 0. Inherited from EditorDescriptor.
  • IncreaseCommand – Sets the command which is executed by the increase repeat button click event. While it is possible to set a custom command, a default one is provided which will suffice in most scenarios.
  • Increment – Determines the numerical distance one click on the spinner button increments or decrements the current value. By default this value is 1 for integers and for doubles the difference between MinValue and MaxValue devided by 200, if both are set, otherwise 1.
  • MaxValue – Set the maximum value. By default this is Double.MaxValue.
  • MinValue – Set the minimum value. By default this is Double.MinValue.
  • Precision – Sets the precision of the format string.
  • RepeatDelay – Sets the duration in milliseconds from when the repeat button is pressed to when it fires its first click event.
  • RepeatInterval – Sets the duration in milliseconds between repeat button click events.

Examples:

[NumericEditorDescriptor(Increment = 0.1, StringFormat = "C")]
public double CurrencyValue { get; set; }
<ctrls:PropertyDefinition TargetPropertyType="{x:Type sys:Double}">
    <ctrls:PropertyDefinition.EditorDescriptorOverride>
        <ctrls:NumericEditorDescriptor EnableInCellEditing="True" MinValue="0" MaxValue="1" Precision="3" EnforceMinMax="True" />
    </ctrls:PropertyDefinition.EditorDescriptorOverride>
</ctrls:PropertyDefinition>

The Primitive Type Collection Editor

Provides an editor for collections of primitive types and strings.

Editor descriptor: PrimitiveCollectionEditorDescriptor.

Editor style resource key: PropertyGridEditor.DefaultPrimitiveTypeCollectionEditorStyleKey.

Properties:

  • EnableInCellEditing. Default value is false. Inherited from EditorDescriptor.
  • FormatString – Default value is null. Inherited from EditorDescriptor.
  • Text – An optional string which is displayed in the cell when EnableInCellEditing is false.

Examples:

[PrimitiveCollectionEditorDescriptor(EnableInCellEditing = true)]
public List<string> StringCollection { get; set; }
<ctrls:PropertyDefinition TargetPropertyName="StringCollection">
    <ctrls:PropertyDefinition.EditorDescriptorOverride>
        <ctrls:PrimitiveCollectionEditorDescriptor EnableInCellEditing="True" Text="(Empty List)" />
    </ctrls:PropertyDefinition.EditorDescriptorOverride>
</ctrls:PropertyDefinition>

The Selector Editor

Provides an editor where a set of possible values is defined from which the user can select one.

Editor descriptor: SelectorEditorDescriptor.

Editor style resource key:

  • PropertyGridEditor.DefaultSelectorEditorStyleKey when PossibleValues is non-null.
  • PropertyGridEditor.DefaultStaticMemberStyleKey when PossibleValuesSource is non-null.

Properties:

  • AutoComplete – An enumeration with Flags attribute. Applies only when Type == DropDown. Possible values are:
    • Off – No auto complete.
    • ReadOnly – Auto complete is enabled. User cannot enter values which are not in the list of possible values.
    • FreeText – Auto complete is enabled and user can enter any value.
    • DontConvertCase – When auto complete is enabled, suggestions are case sensitive.
  • DisplayNames – Defines a list of custom display names for the enum values. If null, then the default enum names are used.
  • EnableInCellEditing. Default value is false. (If AutoComplete is enabled, this value is automatically set to true.) Inherited from EditorDescriptor.
  • FormatString – Default value is null. Inherited from EditorDescriptor.
  • PossibleValues – An array of objects defining the possible values.
  • PossibleValuesSource – A Type which exposes a set of static properties, each of which is a possible value. An example is System.Windows.FontWeights.
  • Type – An enum. Possible values are:
    • DropDown – (Default) the enum values are presented in a drop down.
    • InLine – the enum values are presented directly in the value cell, using radio buttons or check boxes to select by.

Examples:

[SelectorEditorDescriptor("Oak", "Maple", "Walnut", "Almond", "Orange", "Pine", "Redwood", AutoComplete = AutoCompleteOptions.ReadOnly)]
public string Tree { get; set; }
<ctrls:PropertyDefinition TargetPropertyName="StringValue">
    <ctrls:PropertyDefinition.EditorDescriptorOverride>
        <ctrls:SelectorEditorDescriptor EnableInCellEditing="True" AutoComplete="ReadOnly">
            <ctrls:SelectorEditorDescriptor.PossibleValues>
                <sys:String>String 1</sys:String>
                <sys:String>String 2</sys:String> 
                <sys:String>String 3</sys:String>
            </ctrls:SelectorEditorDescriptor.PossibleValues>
        </ctrls:SelectorEditorDescriptor>
    </ctrls:PropertyDefinition.EditorDescriptorOverride>
</ctrls:PropertyDefinition>

Validation

Generating Validation Errors

The default validation mechanism for values entered by the end-user is simply the Type conversion which must take place to convert from a string to the underlying property type. If the conversion throws an exception, the value in invalid and is not/cannot be committed to the underlying property. There are, however, a couple of options in place for customizing this behavior.

To perform property validation from within a single object for the entire property grid, use PropertyGrid.PropertyValidator. PropertyValidator takes an instance of IPropertyGridPropertyValidator, an interface with a single method: Validate(PropertyGridProperty)Validate() should return a string describing the error, if there is an error, or null if the proposed value is valid. The proposed value is available via the Value property of the input parameter at the time Validate() is called.

Validation can also be performed on an individual property basis in two ways. First, the property PropertyGridProperty.Validator is also an IPropertyGridPropertyValidator. If a validator is set up on a property, it takes precedence over one set on the global level. The second mechanism at the property level is via PropertyGridProperty.ValidationCallback, which takes a delegate with input parameter of type PropertyGridProperty and return value of string. The job of the validation callback is the same as for the validator’s Validate method: return null if the property is valid, or a string describing the error.

One final option, which can be implemented in Xaml, is to attach a set of ValidationRule (System.Windows.Controls) instances to a PropertyDefinition. Any rules in the property definition’s ValidationRules collection are added to the Binding which binds the editor’s Value property to the property’s Value property. The validation rules are executed by the system when the binding attempts to update the source. For more information about validation rules, please refer to MSDN documentation for System.Windows.Data.Binding.

Reporting Validation Errors

There are three options for how validation errors are reported to the user in a general sense. The options are defined by the enumeration ValidationErrorNotificationType:

  • None – The user is not notified of the error.
  • MessageBox – A message box is shown with a description of the error.
  • ErrorTemplate – The error is routed through the standard WPF validation mechanism and reported to the user via an ErrorTemplate which is either supplied by default or custom defined by the client.

In all cases, when an error occurs, the underlying property value is unchanged. The error notification type can be set on a global basis via PropertyGrid.ErrorNotification and on an individual property basis via PropertyGridEditor.ErrorNotification.

When error notification is ErrorTemplate the default error template will be used unless overridden. (The default error template is a border with a red brush.) The error template can be overridden through the ValidationErrorTemplate property of a property definition. Alternatively, since Validation.ErrorTemplateProperty is an attached property settable on any UIElement, it is possible to define one for the property grid editor directly.

For more information about validation error templates specifically and the WPF validation mechanism in general, please refer to MSDN documentation for System.Windows.Controls.Validation.

Customizing Visual Appearance

The visual appearance of PropertyGrid and its constituent controls can be changed in a number of ways. Of course, the standard WPF practices for customizing controls are fully supported, including support for custom Styles and Templates.

Many of the resources which define the appearance of the property grid are specified via resource references. The keys for these resources are ComponentResourceKeys. As a general rule, the resource key is defined as a static property on the control class which uses it.

Overriding or customizing a resource which is referenced via a ComponentResourceKey is as simple as defining a new resource and giving it the same key value. Most often, the new resource can be defined in Application or Window Resources. Occasionally, it will be necessary to define the key within the resources collection of the PropertyGrid itself. (This will be the case, especially, if a non-default value for PropertyGrid.VisualStyle has been set.)

Here is an example of a resource with a Key that is a ComponentResourceKey. (This resource defines the border thickness for tool bar contained inside the PropertyGrid.):

<Thickness x:Key="{x:Static ctrls:PropertyGrid.ToolBarBorderThicknessKey}" Left="1" Top="1" Right="1" Bottom="0" />

The resource keys available for this type of customization are generally discoverable as static properties on the class which uses the resource identified.

Control Templates

The default Templates for PropertyGrid and PropertyGridItem are provided for your reference.

<ControlTemplate TargetType="ctrls:PropertyGrid">     <Grid Name="MainGrid" Background="{TemplateBinding Background}">         <Grid.RowDefinitions>             <RowDefinition Height="Auto" />             <RowDefinition />             <RowDefinition Height="Auto" />             <RowDefinition Name="HelpPanelRow" Height="Auto" MaxHeight="{Binding ElementName=HelpPanel, Path=MaxHeight}" MinHeight="{Binding ElementName=HelpPanel, Path=MinHeight}" />         </Grid.RowDefinitions>         <ctrls:AdvToolBar x:Name="ToolBar" KeyboardNavigation.TabNavigation="Continue" FocusManager.IsFocusScope="False" CornerRadius="0" BorderThickness="0"                             ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ToolBarItems}" Padding="4,3" />         <ctrls:PropertyGridItemsControl x:Name="PropertyItemsControl" Grid.Row="1" Margin="0,0.1,1,0" Padding="{TemplateBinding Padding}"                                         KeyboardNavigation.DirectionalNavigation="{TemplateBinding KeyboardNavigation.DirectionalNavigation}"                                          KeyboardNavigation.TabNavigation="{TemplateBinding KeyboardNavigation.TabNavigation}"                                         ScrollViewer.HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"                                          ScrollViewer.VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"                                          ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Properties}">             <ItemsControl.GroupStyle>                 <GroupStyle HidesIfEmpty="True" ContainerStyle="{StaticResource {x:Static ctrls:PropertyGrid.CategoryGroupItemStyleKey}}" />             </ItemsControl.GroupStyle>         </ctrls:PropertyGridItemsControl>         <GridSplitter Name="GridSplitter" Grid.Row="2" IsTabStop="False" ResizeBehavior="PreviousAndNext"  ResizeDirection="Rows"                                                                    SnapsToDevicePixels="True" FocusVisualStyle="{x:Null}" HorizontalAlignment="Stretch"                          Height="{DynamicResource {x:Static ctrls:PropertyGrid.HelpPanelResizeThumbHeightKey}}"                         BorderThickness="0,1"                         BorderBrush="{DynamicResource {x:Static ctrls:PropertyGrid.HelpPanelResizeThumbBorderBrushKey}}"                          Background="{DynamicResource {x:Static ctrls:PropertyGrid.HelpPanelResizeThumbBackgroundKey}}">             <GridSplitter.Template>                 <ControlTemplate TargetType="GridSplitter">                     <Grid Background="Transparent">                         <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" />                     </Grid>                 </ControlTemplate>             </GridSplitter.Template>         </GridSplitter>                                      <Control Name="HelpPanel" Grid.Row="3" DataContext="{TemplateBinding SelectedProperty}" Style="{DynamicResource {x:Static ctrls:PropertyGrid.HelpPanelStyleKey}}" />         <Rectangle Grid.Row="0" VerticalAlignment="Bottom" Height="1" Fill="{TemplateBinding BorderBrush}" />         <Border Grid.RowSpan="4" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" />                              </Grid>     <ControlTemplate.Triggers>         <Trigger Property="ShowHelpPanel" Value="False">             <Setter TargetName="HelpPanel" Property="Visibility" Value="Collapsed" />             <Setter TargetName="GridSplitter" Property="Visibility" Value="Collapsed" />         </Trigger>         <Trigger Property="ShowToolBar" Value="False">             <Setter TargetName="ToolBar" Property="Visibility" Value="Collapsed" />         </Trigger>     </ControlTemplate.Triggers>
</ControlTemplate>

 

<ControlTemplate TargetType="ctrls:PropertyGridItem">
    <Border SnapsToDevicePixels="True" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}">
        <Grid Name="MainGrid" Background="Transparent">
            <Grid.Resources>
                <BooleanToVisibilityConverter x:Key="boolToVisibilityConverter" />
            </Grid.Resources>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType=ctrls:PropertyGrid}, Path=InnerLeftMargin}" />
                <ColumnDefinition Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Indent}" />
                <ColumnDefinition Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=NameColumnWidth}" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition />
            </Grid.RowDefinitions>
                            
            <Border Name="SelectedBorder" Grid.Column="0" Grid.ColumnSpan="3" Opacity="0" SnapsToDevicePixels="True"                     Background="{DynamicResource {x:Static ctrls:PropertyGridItem.SelectedHeaderBackgroundKey}}" />
 
            <Rectangle Name="LeftMarginFill" Grid.RowSpan="3" Fill="{DynamicResource {x:Static ctrls:PropertyGrid.LeftMarginBackgroundKey}}" />
 
            <ToggleButton Name="Expander" HorizontalAlignment="Center" Opacity="0" Focusable="False"                             IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsExpanded, Mode=TwoWay}"                             Style="{DynamicResource {x:Static ctrls:PropertyGridItem.ExpanderToggleButtonStyleKey}}" />
 
            <ContentPresenter Name="HeaderPresenter" Focusable="False" Grid.Column="2"                                 VerticalAlignment="{TemplateBinding VerticalContentAlignment}"                                  Margin="{TemplateBinding CellPadding}" Content="{TemplateBinding Header}"                                   ContentTemplate="{TemplateBinding HeaderTemplate}" ContentStringFormat="{TemplateBinding HeaderStringFormat}">
                <ContentPresenter.ToolTip>
                    <ToolTip Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}"                                  Style="{DynamicResource {x:Static ctrls:PropertyGridItem.ToolTipStyleKey}}" />
                </ContentPresenter.ToolTip>
            </ContentPresenter>
 
            <Button Name="AdvancedPropertiesButton" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,8,0"                      Command="{TemplateBinding AdvancedPropertiesButtonCommand}" CommandParameter="{TemplateBinding DataContext}" Style="{TemplateBinding AdvancedPropertiesButtonStyle}"                     Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ShowAdvancedPropertiesButton, Converter={StaticResource boolToVisibilityConverter}}" />
 
            <ctrls:PropertyGridEditor x:Name="Editor" Grid.Column="3" Padding="{TemplateBinding CellPadding}" Style="{TemplateBinding EditorStyle}" />
 
            <ContentControl Name="InRowEditorContentHost" Focusable="False" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" BorderThickness="0,1,0,0"                              BorderBrush="{DynamicResource {x:Static ctrls:PropertyGrid.HorizontalGridLineBrushKey}}"                              Visibility="Collapsed" HorizontalContentAlignment="Center" />
                            
            <ItemsPresenter Name="ItemsHost" Grid.Row="2" Grid.ColumnSpan="4"                             Visibility="{Binding ElementName=Expander, Path=IsChecked, Converter={StaticResource boolToVisibilityConverter}}" />
            <Thumb Name="ResizeThumb" Grid.Column="2" Margin="0,0,-3,0" Padding="3,0" Cursor="SizeWE" HorizontalAlignment="Right">
                <Thumb.Template>
                    <ControlTemplate>
                        <Grid Background="Transparent">
                            <Rectangle Margin="{TemplateBinding Padding}" Width="1" Fill="{DynamicResource {x:Static ctrls:PropertyGrid.VerticalGridLineBrushKey}}" />
                        </Grid>
                    </ControlTemplate>
                </Thumb.Template>
            </Thumb>
        </Grid>
    </Border>
    <ControlTemplate.Triggers>                        
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ctrls:PropertyGrid}, Path=ExpanderAlignment}" Value="Indented">
            <Setter TargetName="Expander" Property="Grid.ColumnSpan" Value="2" />
            <Setter TargetName="SelectedBorder" Property="Grid.Column" Value="2" />
            <Setter TargetName="SelectedBorder" Property="Grid.ColumnSpan" Value="1" />
        </DataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=ctrls:PropertyGrid}, Path=ExpanderAlignment}" Value="Indented" />
                <Condition Binding="{Binding IsSubProperty}" Value="True" />
            </MultiDataTrigger.Conditions>
            <Setter TargetName="Expander" Property="HorizontalAlignment" Value="Right" />
            <Setter TargetName="InRowEditorContentHost" Property="Grid.Column" Value="2" />
            <Setter TargetName="LeftMarginFill" Property="Opacity" Value="0" />
        </MultiDataTrigger>
        <Trigger SourceName="Editor" Property="IsReadOnly" Value="True">
            <Setter TargetName="HeaderPresenter" Property="ContentTemplate" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=HeaderReadOnlyTemplate}" />
        </Trigger>
        <DataTrigger Binding="{Binding IsSubProperty}" Value="True">
            <Setter Property="BorderThickness" Value="0,1,0,0" />
        </DataTrigger>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ctrls:PropertyGrid}}, Path=ShowToolTips}" Value="False">
            <Setter TargetName="HeaderPresenter" Property="ToolTip" Value="{x:Null}" />
        </DataTrigger>
        <Trigger Property="HasItems" Value="True">
            <Setter TargetName="Expander" Property="Opacity" Value="1" />
        </Trigger>
        <Trigger Property="IsSelected" Value="True">
            <Setter TargetName="SelectedBorder" Property="Opacity" Value="1" />
            <Setter TargetName="HeaderPresenter" Property="TextBlock.Foreground" Value="{DynamicResource {x:Static ctrls:PropertyGridItem.SelectedHeaderForegroundKey}}" />
        </Trigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ctrls:PropertyGrid}}, Path=IsActive}" Value="False" />
                <Condition Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ctrls:PropertyGrid}}, Path=IsSelectionFocusAware}" Value="True" />
                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True" />
            </MultiDataTrigger.Conditions>
            <Setter TargetName="SelectedBorder" Property="Background" Value="{DynamicResource {x:Static ctrls:PropertyGridItem.InactiveSelectedHeaderBackgroundKey}}" />
            <Setter TargetName="HeaderPresenter" Property="TextBlock.Foreground" Value="Black" />
        </MultiDataTrigger>
        <DataTrigger Binding="{Binding ElementName=LeftMarginFill, Path=(Rectangle.Fill).(SolidColorBrush.Color)}" Value="Transparent">
            <Setter TargetName="InRowEditorContentHost" Property="Grid.Column" Value="0" />
            <Setter TargetName="InRowEditorContentHost" Property="Grid.ColumnSpan" Value="4" />
        </DataTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

Related posts:

  1. How to make a password editor in WPF PropertyGrid.
  2. Brush Control Quick Start Guide
  3. Circular Progress Control (WPF) Quick Start Guide
  4. WPF Color Control Quick Start Guide
  5. Rating Control for WPF Quick Start Guide