Dynamic DropDown Properties on the PropertyGrid






4.40/5 (8 votes)
Jul 19, 2007
3 min read

80496

2405
Explains how to add a dynamic dropdown property to the propertygrid at runtime and gives a detailed exampl

Introduction
Dropdown lists in the PropertyGrid provide an easy way to set up controls at design time. However, in some cases the options presented may not be known ahead of time or may vary based on some other setting. VB.NET does not provide an easy way to change the options available. This article gives a concise example of how to implement a dynamic dropdown property in the PropertyGrid.
Background
The code presented here brings together the following resources and combines them into a simple-to-use VB.Net solution:
Using the code
Dynamic dropdown properties are composed of three distinct items:
- A global list of values
- A type converter
- The property definition
Global values
In order for a list of values to appear in a dropdown list of the PropertyGrid, they must be accessible to our type converter. If we want to be able to change the list of values from within our class, they must also be accessable to the class. The solution to this is to place our list of values in an array located globally within the namespace. Here, we create a global class, GlobalClass
, which wraps a string array OptionStringArray
that will be used to hold the values displayed in our dropdown list.
Friend Class GlobalClass
'This class is global to the namespace and can be altered by our control.
'It can also be read by our OptionConverter to provide a general type.
'It has all the dangers of any global variable and
'can be accessed by other assemblies.
Friend Shared OptionStringArray(0) As String
'Holds the options available in the dropdown
End Class
Type converter
A type converter provides a unified way of converting types of values into other types. The OptionConverter
overloads the GetStandardValuesSupported
, GetStandardValuesExclusive
, and GetStandardValues
methods of its inherited StingConverter
class. GetStandardValuesSupported
returns true
, indicating that the type supports standard values and that the PropertyGrid should display these values within a dropdown combo box. GetStandardValuesExclusive
returns true
to indicate that the standard values are locked and will not support freeform entry. GetStandardValues
returns the StandardValuesCollection
value created from GlobalClass.OptionStringArray
. This collection is what is used to populate the dropdown list.
Public Class OptionConverter
'This will act as a typeconverter and present
'our collection to the property grid
Inherits StringConverter
Public Overloads Overrides Function GetStandardValuesSupported( _
ByVal context As ITypeDescriptorContext) As Boolean
Return True 'True tells the propertygrid to display a combobox
End Function
Public Overloads Overrides Function GetStandardValuesExclusive( _
ByVal context As ITypeDescriptorContext) As Boolean
Return True 'True makes the combobox select only.
'False allows free text entry.
End Function
Public Overloads Overrides Function GetStandardValues( _
ByVal context As ITypeDescriptorContext) As StandardValuesCollection
Return New StandardValuesCollection(GlobalClass.OptionStringArray)
'Exports our global collection of options
End Function
End Class
Property definition
The property definition can be divided into three sections:
- The local variable
- The exposed property
- The default values
Local variable
The local variable simply holds the selected option.
Private _SelectedOption As String 'Holds the selected option
Exposed property
OptionConverter
is passed to the type converter and presents the GlobqalClass.OtionStringArray
to the PropertyGrid as a selection list. If an item has already been selected and is in the local variable _SelectedOption
, it is returned by the Get
method. If no item is selected, then the first option is returned. When the Set
method is employed, the local variable _SelectedOption
is set to the value that is passed in.
<Browsable(True), TypeConverter(GetType(OptionConverter))> _
Public Property OptionList() As String
'Property displayed it the property grid
Get
Dim TempString As String = ""
'Holds our selected option for return
If _SelectedOption Is Nothing Then
'If an option has not already been selected
If GlobalClass.OptionStringArray.GetUpperBound(0) > 0 Then
'If there is more than 1 option
Array.Sort(GlobalClass.OptionStringArray)
'Sort them alphabetically
End If
TempString = GlobalClass.OptionStringArray(0)
'Choose the first option (or the empty one)
Else 'Otherwise, if the option is already selected
TempString = _SelectedOption
'Choose the already selected value
End If
Return TempString
'Return the selected option, the first option, or an empty option
End Get
Set(ByVal Value As String)
_SelectedOption = Value
'When a selection is made update the selected option
End Set
End Property
Default values
Because DefaultValueAttribute
requires a constant and our dropdown property list is dynamic, we need to use an alternate method to provide a default value. This will both allow the dynamic default to appear in regular text in the property grid and allow the value to be reset to the default using the right click "reset" option.
Two methods are used to produce this behavior: ShouldSerializeOptionList()
and ResetOptionList()
. These methods must end in the exact same name as the exposed property or they will not work. If _SelectedOption
is equal the the desired default option, then false
should be returned by ShouldSerializeOptionList()
. Otherwise, ShouldSerializeOptionList()
should return true
to indicate that a bold font should be used. When ResetOptionList()
is called, the SelectedOption
should be changed back to the default option.
Public Function ShouldSerializeOptionList() As Boolean
'Sets a dynamic "DefualtValueAttribute" for the property
'This uses a poorly documented feature of PropertyGrid and
'should be used in
'conjunction with the Reset... method.
'
'When the PropertyGrid displays a value, it determines
'whether to show the value
'in bold by checking first for a DefaultValueAttribute.
'
'If no DefaultValueAttribute is found, then the
'PropertyGrid uses reflection
'to see if a method with the name ShouldSerialize... exists.
'(where ... exactly matches the property name)
'
'If the method does exist, the PropertyGrid calls it.
'A return value of true
'produces bold text, false produces regular text.
Return Not _SelectedOption = GlobalClass.OptionStringArray(0)
End Function
Public Sub ResetOptionList()
'Resets to the dynamic "DefualtValueAttribute" for the Device
'This uses a poorly documented feature of PropertyGrid and
'should be used in
'conjunction with the ShouldSerialize... method.
'
'When the PropertyGrid resets a value, it determines the correct value
'by checking first for a DefaultValueAttribute.
'
'If no DefaultValueAttribute is found then the
'PropertyGrid uses reflection
'to see if a method with the name Reset... exists.
'(where ... exactly matches the property name)
'
'If the method does exist, the propertygrid calls it
'to reset the property to
'the default value.
_SelectedOption = GlobalClass.OptionStringArray(0)
End Sub
Points of interest
To change the contents of the dropdown list, redim the GlobalClass.OptionStringArray
to the desired size and set each element to the desired value. An example is provided below.
Private _NumberOfDynamicOptions As Integer 'Holds number of options
Public Property NumberOfDynamicOptions() As Integer
'Allows the number of options to change dynamically
Get
Return _NumberOfDynamicOptions
'Returns the current number of options displayed
End Get
Set(ByVal Value As Integer)
If Value < 0 Then 'If the number entered is negative
_NumberOfDynamicOptions = 0 'Use zero instead
ElseIf Value > 100 Then 'And if the number is over 100
_NumberOfDynamicOptions = 100 'Just use 100
Else 'Otherwise, if the number is between 0 and 100 (inclusive)
_NumberOfDynamicOptions = Value
'Set it as our new number of options
End If
ReDim GlobalClass.OptionStringArray(_NumberOfDynamicOptions)
'Resize the array
Dim LoopCount As Integer 'Loop variable
For LoopCount = 0 To _NumberOfDynamicOptions
'Loop up to the number of options
GlobalClass.OptionStringArray(LoopCount) = _
LoopCount.ToString + " " + Chr(33 + LoopCount).ToString
'Set each option equal to the count and a character
Next
End Set
End Property
History
- 19 July, 2007 -- Original version posted