Skip to main content

Property Categories

  • 4 minutes to read

Overview

The PropertyGrid control can divide the properties of the bound object into categories. Properties from the same category are displayed within an expandable group. To specify a category, decorate a property of the bound object with the Category attribute. The PropertyGrid control automatically generates category rows based on the category attribute values.

The following example demonstrates how to decorate properties of the bound object with the category attribute.

[Category("Contact")]
public string Email { get; set; }
[Category("Address")]
public string AddressLine1 { get; set; }

Users can switch between categorized and flat display modes at runtime using the tool panel. To specify the default category display mode, use the PropertyGridControl.ShowCategories property. The image below demonstrates both display modes.

PG_flat_categorized

Set the ExpandCategoriesWhenSelectedObjectChanged property to true to automatically expand all categories when the user selects another object.

Using Category Definitions

Category definitions represent the category rows and specify their appearance within the property grid. Category definitions are represented by theCategoryDefinition objects that are stored within the PropertyGridControl.PropertyDefinitions collection.

The following example demonstrates the CategoryDefinition objects that specify the custom category headers.

using System.ComponentModel;
...
public class Supplier {
    [Category("Info")]
    public int ID { get; set; }
    [Category("Info")]
    public string Name { get; set; }
    [Category("Contact")]
    public string Email { get; set; }
    [Category("Contact")]
    public string Phone { get; set; }
}

public class ViewModel {
    public Supplier DemoSupplier { get; set; }
    public ViewModel() {
        DemoSupplier = new Supplier()
        {
            ID = 0,
            Name = "Anita Benson",
            Email = "Anita_Benson@example.com",
            Phone = "7138638137"
        };
    }
}
<Window.DataContext>
    <local:ViewModel/>
</Window.DataContext>
...
<dxprg:PropertyGridControl SelectedObject="{Binding DemoSupplier}"
                           ShowProperties="All" ShowCategories="Visible">
    <dxprg:CategoryDefinition Path="Info" Header="Personal Information"/>
    <dxprg:CategoryDefinition Path="Contact" Header="Contact Information"/>
</dxprg:PropertyGridControl>

The image below demonstrates the result.

PG_Category_Visible

Tabbed View

To display each category in a separate tab, set the PropertyGridControl.ShowCategories property to Tabbed.

PG_Category_Tabbed

The following example demonstrates how to use the CategoryDefinition objects to specify a glyph for each tab header.

using System.ComponentModel;

public class Supplier {
    [Category("Info")]
    public int ID { get; set; }
    [Category("Info")]
    public string Name { get; set; }
    [Category("Contact")]
    public string Email { get; set; }
    [Category("Contact")]
    public string Phone { get; set; }
}

public class ViewModel {
    public Supplier DemoSupplier { get; set; }
    public ViewModel() {
        DemoSupplier = new Supplier()
        {
            ID = 0,
            Name = "Anita Benson",
            Email = "Anita_Benson@example.com",
            Phone = "7138638137"
        };
    }
}
<Window 
        ...
        xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core">
<Window.DataContext>
    <local:ViewModel/>
</Window.DataContext>
...
<dxprg:PropertyGridControl SelectedObject="{Binding DemoSupplier}" ShowProperties="All" ShowCategories="Tabbed">
    <dxprg:CategoryDefinition Path="Info" Glyph="{dx:DXImage Image=Female_32x32.png}"/>
    <dxprg:CategoryDefinition Path="Contact" Glyph="{dx:DXImage Image=Contact_32x32.png}"/>
</dxprg:PropertyGridControl>

Applying Mode

You can create different property definitions for each of the display modes. The PropertyDefinitionBase.ApplyingMode property specifies whether a property definition should be applied in the categorized or flat mode.

The example below demonstrates a property grid that is configured in the following way.

  • The ID property is visible in both the flat and categorized display modes.
  • The Email property is visible in the categorized mode only.
  • The Name property has different descriptions in each of the display modes.
<dxprg:PropertyGridControl SelectedObject="{Binding DemoSupplier}" ShowProperties="WithPropertyDefinitions">
    <dxprg:CategoryDefinition Path="Info" Header="Personal Information"/>
    <dxprg:CategoryDefinition Path="Contact" Header="Contact Information"/>

    <dxprg:PropertyDefinition Path="ID" Description="Customer's ID" ApplyingMode="Always"/>
    <dxprg:PropertyDefinition Path="Email" Description="Email" ApplyingMode="WhenGrouping"/>
    <dxprg:PropertyDefinition Path="Name" Description="Name Catagorized" ApplyingMode="WhenGrouping"/>
    <dxprg:PropertyDefinition Path="Name" Description="Name Flat" ApplyingMode="WhenNoGrouping"/>
</dxprg:PropertyGridControl>

PG_ApplyingMode

Limitation

If you have two definitions with equal Path property values and different PropertyDefinitionBase.ApplyingModes, the PropertyGridControl does not update its property definitions when you switch the PropertyGridControl.ShowCategories property’s value at runtime.

<dxprg:PropertyGridControl SelectedObject="{Binding DemoSupplier}" ShowProperties="WithPropertyDefinitions">
    <dxprg:PropertyDefinition Path="Name" Description="Name Catagorized" ApplyingMode="WhenGrouping"/>
    <dxprg:PropertyDefinition Path="Name" Description="Name Flat" ApplyingMode="WhenNoGrouping"/>
</dxprg:PropertyGridControl>

You can declare a custom PropertyGridControl descendant and override its OnShowCategoriesChanged method to force the PropertyGridControl to regenerate its definitions when you change ShowCategories mode:

public class MyPropertyGridControl : PropertyGridControl {
    protected override void OnShowCategoriesChanged(CategoriesShowMode oldValue) {
        base.OnShowCategoriesChanged(oldValue);
        this.DataController.ResetCache();
    }
} 
See Also