This code tells your PropertyGrid control how to work with Properties which represent a custom Class
This also works dynamically, so you don’t have to create TypeConverters and UITypeEditors for each custom Class. It discerns which Property it’s representing via a Property Attribute UniqueIdetifier
First, adding the UniqueIdentifier
custom Property Attribute:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Public Class UniqueIdentifier Inherits Attribute Private _identifier As String Public Property Identifier() As String Get Return _identifier End Get Set(ByVal value As String) _identifier = value End Set End Property Public Sub New(identifier As String) _identifier = identifier End Sub End Class |
Then, two POCO classes demonstrating the data objects to be used:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
Imports System.ComponentModel Imports System.Drawing.Design Public Class Employee Public Property Name <UniqueIdentifier("Name.PrimaryTeam")> <Editor(GetType(CustomClassDropDownEditor), GetType(UITypeEditor))> Public Property PrimaryTeam As Team Public Overrides Function ToString() As System.String Return Name & "; " & PrimaryTeam End Function End Class ' This instructs PropertyGrids to use this TypeConverter when rendering the class to a string <TypeConverter(GetType(CustomClassDropDownConverter))> Public Class Team Public Property Name Public Property TelNumber As String Public Overrides Function ToString() As System.String Return Name End Function End Class |
Note
<TypeConverter(GetType(CustomClassDropDownConverter))> This is important. Next, some sample data for Teams
:
1 2 3 4 5 6 7 8 9 10 11 |
Public Class Main Public Shared Property Teams As New List(Of Team) Public Sub New() Teams.Add(New Team With {.Name = "Personnel", .TelNumber = "0800 892 654"}) Teams.Add(New Team With {.Name = "Pest Control", .TelNumber = "0800 624 854"}) Teams.Add(New Team With {.Name = "Whitewash Team", .TelNumber = "0800 243 111"}) End Sub End Class |
Next the TypeConverter
that tells the PropertyGrid
how to render the Team Class into a single string:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
Imports System.ComponentModel Imports System.Globalization Imports System.Linq ' This tells the PropertyGrid how to convert the Class to a single string (displayed in the grid) Public Class CustomClassDropDownConverter Inherits TypeConverter Public Overrides Function CanConvertTo(ByVal context As ITypeDescriptorContext, ByVal destinationType As Type) As Boolean If destinationType Is GetType(String) Then Return True End If End Function Public Overrides Function ConvertTo(ByVal context As ITypeDescriptorContext, ByVal culture As CultureInfo, ByVal value As Object, ByVal destinationType As Type) As Object Dim att As UniqueIdentifier = context.PropertyDescriptor.Attributes.OfType(Of UniqueIdentifier)().First If destinationType Is GetType(String) Then Select Case att.Identifier Case "Name.PrimaryTeam" Dim team As Team = TryCast(value, Team) If team IsNot Nothing Then Return team.Name End Select End If Return "(none)" End Function End Class |
Finally, the UITypeEditor
that produces the drop-down list in the PropertyGrid
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
Imports System.ComponentModel Imports System.Drawing.Design Imports System.Windows.Forms Imports System.Windows.Forms.Design ' This provides a drop-down menu in the PropertyGrid to select the relevant Class Member Public Class CustomClassDropDownEditor Inherits UITypeEditor Private editorService As IWindowsFormsEditorService Public Overrides Function GetEditStyle(ByVal context As ITypeDescriptorContext) As UITypeEditorEditStyle Return UITypeEditorEditStyle.DropDown End Function Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, ByVal provider As IServiceProvider, ByVal value As Object) As Object editorService = CType(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService) Dim PropertyUniqueID As String = Nothing For Each att In context.PropertyDescriptor.Attributes If TypeOf att Is UniqueIdentifier Then PropertyUniqueID = att.Identifier Next Dim lb As ListBox = New ListBox With {.SelectionMode = SelectionMode.One} AddHandler lb.SelectedValueChanged, AddressOf OnListBoxSelectedValueChanged Select Case PropertyUniqueID Case "Name.PrimaryTeam" For Each team In Main.Teams Dim index As Integer = lb.Items.Add(team) If team.Equals(value) Then lb.SelectedIndex = index Next End Select editorService.DropDownControl(lb) If lb.SelectedItem Is Nothing Then Return value Return lb.SelectedItem End Function Private Sub OnListBoxSelectedValueChanged(ByVal sender As Object, ByVal e As EventArgs) editorService.CloseDropDown() End Sub End Class |
And that’s it. You should be able to adapt this for use with other property data types such as integers etc.
Leave a Reply