Back to Devexpress

Row Expandability

windowsforms-403204-controls-and-libraries-property-grid-row-expandibility.md

latest5.9 KB
Original Source

Row Expandability

  • Jun 28, 2021
  • 3 minutes to read

The selected object can expose properties that contain child properties. That is, a parent property is a reference to an object whose properties should also be displayed in the control.

The control can display child properties as sub-rows that users can expand with a click on the parent row. To allow the control to generate child rows, you should annotate the parent property (or its type) with a type converter that derives from the ExpandableObjectConverter.

Note

If you create rows in the designer, there is no need to use an expandable object converter. At design time, the control generates sub-rows regardless of whether the converter is applied.

Example

The selected object in this example exposes a parent property that contains two child properties. The control automatically creates sub-rows for child properties.

The code below implements an ExpandableObjectConverter descendant to create a custom converter. This converter is then applied to a type that is the type of the selected object’s parent property.

This custom converter overrides the ConvertTo method to convert the parent object to a string. This string is displayed in the parent row. Child properties are annotated with the NotifyParentPropertyAttribute to notify the parent property about changes in a child property. When a child property changes, the string in the parent row is also updated.

csharp
using System;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;

propertyGridControl.SelectedObject = new DemoObject();

public partial class DemoObject {
    DemoChildObject parentPropertyValue = new DemoChildObject();

    [Category("Demo")]
    public DemoChildObject ParentProperty {
        get {
            return this.parentPropertyValue;
        }

        set {
            this.parentPropertyValue = value;
        }
    }
}

[TypeConverter(typeof(DemoChildObjectConverter))]
public class DemoChildObject {
    private int sizeValue = 1;
    private Color colorValue = Color.Empty;

    [NotifyParentProperty(true),
    DefaultValue(1)]
    public int SizeChildProperty {
        get {
            return sizeValue;
        }
        set {
            if (sizeValue != value) {
                sizeValue = value;
            }
        }
    }

    [NotifyParentProperty(true)]
    [DefaultValue(typeof(Color), "")]
    public Color ColorChildProperty {
        get {
            return colorValue;
        }
        set {
            if (colorValue != value) {
                colorValue = value;
            }
        }
    }
}

public class DemoChildObjectConverter : ExpandableObjectConverter {
    // This method returns a string that is
    // displayed in the parent row.
    public override object ConvertTo(
        ITypeDescriptorContext context,
        CultureInfo culture,
        object value,
        Type destinationType) {
        if (destinationType == typeof(string)) {
            DemoChildObject borderAppearance = value as DemoChildObject;
            return $"Size: {borderAppearance.SizeChildProperty}, Color: {borderAppearance.ColorChildProperty}";
        }

        return base.ConvertTo(
            context,
            culture,
            value,
            destinationType);
    }
}
vb
Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Globalization

propertyGridControl.SelectedObject = New DemoObject()

Public Partial Class DemoObject
    Private parentPropertyValue As DemoChildObject = New DemoChildObject()

    <Category("Demo")>
    Public Property ParentProperty As DemoChildObject
        Get
            Return parentPropertyValue
        End Get
        Set(ByVal value As DemoChildObject)
            parentPropertyValue = value
        End Set
    End Property
End Class

<TypeConverter(GetType(DemoChildObjectConverter))>
Public Class DemoChildObject
    Private sizeValue As Integer = 1
    Private colorValue As Color = Color.Empty

    <NotifyParentProperty(True), DefaultValue(1)>
    Public Property SizeChildProperty As Integer
        Get
            Return sizeValue
        End Get
        Set(ByVal value As Integer)

            If sizeValue <> value Then
                sizeValue = value
            End If
        End Set
    End Property

    <NotifyParentProperty(True)>
    <DefaultValue(GetType(Color), "")>
    Public Property ColorChildProperty As Color
        Get
            Return colorValue
        End Get
        Set(ByVal value As Color)

            If colorValue <> value Then
                colorValue = value
            End If
        End Set
    End Property
End Class

Public Class DemoChildObjectConverter
    Inherits ExpandableObjectConverter
    ' This method returns a string that is
    ' displayed in the parent row.
    Public Overrides Function ConvertTo(ByVal context As ITypeDescriptorContext, ByVal culture As CultureInfo, ByVal value As Object, ByVal destinationType As Type) As Object
        If destinationType Is GetType(String) Then
            Dim borderAppearance As DemoChildObject = TryCast(value, DemoChildObject)
            Return $"Size: {borderAppearance.SizeChildProperty}, Color: {borderAppearance.ColorChildProperty}"
        End If

        Return MyBase.ConvertTo(context, culture, value, destinationType)
    End Function
End Class