New to Telerik UI for WinForms? Download free 30-day trial

Custom Items

RadPropertyGrid allows you to create and use your own custom value items, allowing you to add the desired editors to fit your business need. In the following example, we will add two radio buttons as value editor for a property grid item.

Figure 1: Custom Property Grid Item

WinForms RadPropertyGrid Custom Property Grid Item

Let’s start by specifying the RadPropertyGrid.SelectedObject property, so out controls gets populated with some data. For this purpose, we will use the Item class which is defined below:

Data Class

public class Item
{
    public int Id { get; set; }
    public string Title { get; set; }
    public DeliveryType DeliveryType { get; set; }
    public Item(int id, string title, DeliveryType deliveryType)
    {
        this.Id = id;
        this.Title = title;
        this.DeliveryType = deliveryType;
    }
}
public enum DeliveryType
{
    Delivery,
    PickUp,
}

Public Class Item
    Public Property Id() As Integer
        Get
            Return m_Id
        End Get
        Set(value As Integer)
            m_Id = value
        End Set
    End Property
    Private m_Id As Integer
    Public Property Title() As String
        Get
            Return m_Title
        End Get
        Set(value As String)
            m_Title = value
        End Set
    End Property
    Private m_Title As String
    Public Property DeliveryType() As DeliveryType
        Get
            Return m_DeliveryType
        End Get
        Set(value As DeliveryType)
            m_DeliveryType = value
        End Set
    End Property
    Private m_DeliveryType As DeliveryType
    Public Sub New(id As Integer, title As String, deliveryType As DeliveryType)
        Me.Id = id
        Me.Title = title
        Me.DeliveryType = deliveryType
    End Sub
End Class
Public Enum DeliveryType
    Delivery
    PickUp
End Enum

Next, we should create a custom PropertyGridValueElement which is purposed to be used in a derived PropertyGridItemElement. Our custom implementation of the PropertyGridValueElement will demonstrate how to insert radio buttons for the Item.DeliveryType property.

Custom PropertyGridValueElement

public class CustomPropertyGridValueElement : PropertyGridValueElement
{
    StackLayoutElement stackPanel;
    protected override void CreateChildElements()
    {
        base.CreateChildElements();
        stackPanel = new StackLayoutElement();
        stackPanel.Orientation = Orientation.Vertical;
        foreach (var enumItem in Enum.GetValues(typeof(DeliveryType)))
        {
            RadRadioButtonElement rb = new RadRadioButtonElement();
            rb.Text = enumItem.ToString();
            rb.ToggleStateChanged += rb_ToggleStateChanged;
            stackPanel.Children.Add(rb);
        }
        this.Children.Add(stackPanel);
    }
    private void rb_ToggleStateChanged(object sender, StateChangedEventArgs args)
    {
        RadRadioButtonElement rb = sender as RadRadioButtonElement;
        PropertyGridItem item = this.VisualItem.Data as PropertyGridItem;
        if (item != null && rb.Text != item.FormattedValue && rb.ToggleState == ToggleState.On)
        {
            item.Value = rb.Text;
        }
    }
    public override void Synchronize()
    {
        PropertyGridItem item = this.VisualItem.Data as PropertyGridItem;
        foreach (RadRadioButtonElement rb in stackPanel.Children)
        {
            if (rb.Text == item.FormattedValue)
            {
                rb.ToggleState = ToggleState.On;
                break;
            }
        }
    }
}

Public Class CustomPropertyGridValueElement
Inherits PropertyGridValueElement
    Private stackPanel As StackLayoutElement
    Protected Overrides Sub CreateChildElements()
        MyBase.CreateChildElements()
        stackPanel = New StackLayoutElement()
        stackPanel.Orientation = Orientation.Vertical
        For Each enumItem As Object In [Enum].GetValues(GetType(DeliveryType))
            Dim rb As New RadRadioButtonElement()
            rb.Text = enumItem.ToString()
            AddHandler rb.ToggleStateChanged, AddressOf rb_ToggleStateChanged
            stackPanel.Children.Add(rb)
        Next
        Me.Children.Add(stackPanel)
    End Sub
    Private Sub rb_ToggleStateChanged(sender As Object, args As StateChangedEventArgs)
        Dim rb As RadRadioButtonElement = TryCast(sender, RadRadioButtonElement)
        Dim item As PropertyGridItem = TryCast(Me.VisualItem.Data, PropertyGridItem)
        If item IsNot Nothing AndAlso rb.Text <> item.FormattedValue AndAlso rb.ToggleState = ToggleState.[On] Then
            item.Value = rb.Text
        End If
    End Sub
    Public Overrides Sub Synchronize()
        Dim item As PropertyGridItem = TryCast(Me.VisualItem.Data, PropertyGridItem)
        For Each rb As RadRadioButtonElement In stackPanel.Children
            If rb.Text = item.FormattedValue Then
                rb.ToggleState = ToggleState.[On]
                Exit For
            End If
        Next
    End Sub
End Class

To put this value element in action, we will create a descendant of PropertyGridItemElement, and we will override its CreatePropertyGridValueElement method. In order to avoid reusing of the custom element for other items, you can override the PropertyGridItemElement. IsCompatible method and control whether the custom element is applicable for the specific PropertyGridItem . In addition, it is necessary to create another PropertyGridItemElement which is not compatible with your custom item:

Custom PropertyGridItemElements

public class CustomItemElement : PropertyGridItemElement
{
    protected override PropertyGridValueElement CreatePropertyGridValueElement()
    {
        return new CustomPropertyGridValueElement();
    }
    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(PropertyGridItemElement);
        }
    }
    public override bool IsCompatible(PropertyGridItemBase data, object context)
    {
        return data.Label == "DeliveryType";
    }
}
public class DefaultPropertyGridItemElement : PropertyGridItemElement
{
    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(PropertyGridItemElement);
        }
    }
    public override bool IsCompatible(PropertyGridItemBase data, object context)
    {
        return data.Label != "DeliveryType";
    }
}

Public Class CustomItemElement
Inherits PropertyGridItemElement
    Protected Overrides Function CreatePropertyGridValueElement() As PropertyGridValueElement
        Return New CustomPropertyGridValueElement()
    End Function
    Protected Overrides ReadOnly Property ThemeEffectiveType() As Type
        Get
            Return GetType(PropertyGridItemElement)
        End Get
    End Property
    Public Overrides Function IsCompatible(data As PropertyGridItemBase, context As Object) As Boolean
        Return data.Label = "DeliveryType"
    End Function
End Class
Public Class DefaultPropertyGridItemElement
    Inherits PropertyGridItemElement
    Protected Overrides ReadOnly Property ThemeEffectiveType() As Type
        Get
            Return GetType(PropertyGridItemElement)
        End Get
    End Property
    Public Overrides Function IsCompatible(data As PropertyGridItemBase, context As Object) As Boolean
        Return data.Label <> "DeliveryType"
    End Function
End Class

Back to the control, let’s subscribe to the RadPropertyGrid.CreateItemElement event which gives you the opportunity to replace the item created for the DeliveryType property with your custom one:

Handle CreateItemElement Event

private void radPropertyGrid1_CreateItemElement(object sender,
CreatePropertyGridItemElementEventArgs e)
{
    if (e.ItemElementType == typeof(PropertyGridItemElement))
    {
        if (e.Item.Name == "DeliveryType")
        {
            e.ItemElementType = typeof(CustomItemElement);
        }
        else
        {
            e.ItemElementType = typeof(DefaultPropertyGridItemElement);
        }
    }
}

Private Sub radPropertyGrid1_CreateItemElement(sender As Object, e As CreatePropertyGridItemElementEventArgs)
    If e.ItemElementType = GetType(PropertyGridItemElement) Then
        If e.Item.Name = "DeliveryType" Then
            e.ItemElementType = GetType(CustomItemElement)
        Else
            e.ItemElementType = GetType(DefaultPropertyGridItemElement)
        End If
    End If
End Sub

The next thing we need to do is to stop entering edit mode when clicking over one of the radio buttons by using the RadPropertyGrid.Editing event. Thus, the user will be allowed to select directly the preferred delivery type without necessity to enter edit mode.

Handle Editing Event

private void radPropertyGrid1_Editing(object sender,
    PropertyGridItemEditingEventArgs e)
{
    if (e.Item.Name == "DeliveryType")
    {
        e.Cancel = true;
    }
}

Private Sub radPropertyGrid1_Editing(sender As Object, e As PropertyGridItemEditingEventArgs)
    If e.Item.Name = "DeliveryType" Then
        e.Cancel = True
    End If
End Sub

The last thing we should update is to adjust the PropertyGridElement.PropertyTableElement.ItemHeight property with such a value to fit the available content:

Set Item Height

this.radPropertyGrid1.PropertyGridElement.PropertyTableElement.ItemHeight = Enum.GetValues(typeof(DeliveryType)).Length * 20;

Me.radPropertyGrid1.PropertyGridElement.PropertyTableElement.ItemHeight = [Enum].GetValues(GetType(DeliveryType)).Length * 20

As of R3 2021 SP1 RadPropertyGrid supports individual item's height. As the control does not expose the items directly, there is no Items collection, the data item can be accessed in the CreateItemElement or the ItemFormatting event. Then, specify the Item.ItemHeight property to the desired height.

See Also

In this article