Introduction
For my last project, I had a requirement where I can use PropertyGrid
control. I tried to get information on that, from Microsoft and searching all over Internet, newsgroups, but I could find only a couple of articles from Microsoft. That's it, surprising, and not even a single example in VB.NET that compiles without errors and explains all in and outs of PropertyGrid
control.
So, I decided to put all the information I collected, with fully functional working examples in VB.NET (which is my favorite) and let me tell you, it is the most complex control of all controls in VS.NET, yet very powerful and extremely useful, particularly in Custom Controls, and for Application Configuration settings. Visual Studio .NET property browser is also based upon the PropertyGrid
.
Its so complex that I have to split this article into two parts. In this Part-I, I will explain how to use the basic properties and System
resources, and in Part-II I will cover the advanced topic on using Custom Editors and User defined types.
Description
Open a new Windows application project using VB.NET. By default PropertyGrid
is not visible in the Toolbox. So click on Customize Toolbox and add the PropertyGrid
Control.
Adding the control, and dropping it on the Designer is pretty much the same like any other control. Fun starts after that. In order to use the PropertyGrid
control, you have to provide a class as source to the PropertyGrid
. Let's see a small example.
Imports System.ComponentModel
<DefaultPropertyAttribute("Title")> _
Public Class SimpleProperties
Private _Title As String
Private _Show As Boolean
Private _Number As Short
<CategoryAttribute("Application"), _
Browsable(True), _
[ReadOnly](False), _
BindableAttribute(False), _
DefaultValueAttribute(""), _
DesignOnly(False), _
DescriptionAttribute("Enter Title for the application")> _
Public Property Title() As String
Get
Return _Title
End Get
Set(ByVal Value As String)
_Title = Value
End Set
End Property
<CategoryAttribute("Application"), _
Browsable(True), _
[ReadOnly](False), _
BindableAttribute(False), _
DefaultValueAttribute("True"), _
DesignOnly(False), _
DescriptionAttribute("Show option")> _
Public Property Show() As Boolean
Get
Return _Show
End Get
Set(ByVal Value As Boolean)
_Show = Value
End Set
End Property
<CategoryAttribute("Application"), _
Browsable(True), _
[ReadOnly](False), _
BindableAttribute(False), _
DefaultValueAttribute("0"), _
DesignOnly(False), _
DescriptionAttribute("Enter a number")> _
Public Property Number() As Short
Get
Return _Number
End Get
Set(ByVal Value As Short)
_Number = Value
End Set
End Property
End Class
To your form_load
event add the following code:
PropertyGrid1.SelectedObject = New SimpleProperties()
Press F5 to run the project. Let's see the elements in the SimpleProperties.vb class
Imports System.ComponentModel | Required for the Attributes |
DefaultPropertyAttribute("Title") | Indicates the default property for the PropertyGrid (i.e. where cursor is located when loaded) |
CategoryAttribute("Application") | Category attribute indicating the Category to which the property belongs to. Properties belonging to one category are grouped together. |
Browsable(True) | Indicates whether the property is shown in the grid |
[ReadOnly](False) | Indicates that the property is read-only or not |
BindableAttribute(False) | Indicates whether the property can be bound to a data source or not |
DefaultValueAttribute("") | Default value for the property |
DesignOnly(False) | If true , it indicates that the property is Read-only at run time |
DescriptionAttribute("Enter Title for the application") | Property Description. This description appears in the bottom when you click the property. |
Then add the properties that you want to see in the PropertyGrid
with right data types. Finally, assign the Class to the PropertyGrid
's SelectedObject
property. That's all we have to do. Rest is taken care by the PropertyGrid
and you see the following output.
Let's add some System
resources to the above class
Private _ApplicationSize As Size
Private _ApplicationLocation As Point
Private _ApplicationFont As System.Drawing.Font
Private _FontColor As System.Drawing.Color
Private _ApplicationIcon As System.Drawing.Icon
Private _ApplicationCursor As System.Windows.Forms.Cursor
Private _ApplicationLangugae As System.Globalization.CultureInfo
<CategoryAttribute("Design"), DefaultValueAttribute(""), _
DescriptionAttribute("Enter Application size")> _
Public Property ApplicationSize() As Size
Get
Return _ApplicationSize
End Get
Set(ByVal Value As Size)
_ApplicationSize = Value
End Set
End Property
<CategoryAttribute("Design"), DefaultValueAttribute(""), _
DescriptionAttribute("Enter Application Location")> _
Public Property ApplicationLocation() As Point
Get
Return ApplicationLocation
End Get
Set(ByVal Value As Point)
_ApplicationLocation = Value
End Set
End Property
<CategoryAttribute("Design"), DefaultValueAttribute(""), _
DescriptionAttribute("Select font for the application")> _
Public Property ApplicationFont() As System.Drawing.Font
Get
Return _ApplicationFont
End Get
Set(ByVal Value As System.Drawing.Font)
_ApplicationFont = Value
End Set
End Property
<CategoryAttribute("Design"), DefaultValueAttribute(""), _
DescriptionAttribute("Select font color")> _
Public Property FontColor() As System.Drawing.Color
Get
Return _FontColor
End Get
Set(ByVal Value As System.Drawing.Color)
_FontColor = Value
End Set
End Property
<CategoryAttribute("Design"), DefaultValueAttribute(""), _
DescriptionAttribute("Select icon for application")> _
Public Property ApplicationIcon() As System.Drawing.Icon
Get
Return _ApplicationIcon
End Get
Set(ByVal Value As System.Drawing.Icon)
_ApplicationIcon = Value
End Set
End Property
<CategoryAttribute("Design"), DefaultValueAttribute(""), _
DescriptionAttribute("Select application's cursor")> _
Public Property ApplicationCursor() As System.Windows.Forms.Cursor
Get
Return _ApplicationCursor
End Get
Set(ByVal Value As System.Windows.Forms.Cursor)
_ApplicationCursor = Value
End Set
End Property
<CategoryAttribute("Design"), DefaultValueAttribute(""), _
DescriptionAttribute("Select User language")> _
Public Property ApplicationLangugae() As System.Globalization.CultureInfo
Get
Return _ApplicationLangugae
End Get
Set(ByVal Value As System.Globalization.CultureInfo)
_ApplicationLangugae = Value
End Set
End Property
Again, PropertyGrid
automatically populates Enumerations as drop down list, and system structures as collapsible sub sections.
Adding custom dropdown list
Now let's add a custom dropdown list which shows all states. In order to add a custom dropdown list, create a class that inherits from System.ComponentModel.TypeConverter
or any other class, that was derived from TypeConverter
class that matches your datatype. (check for System.ComponentModel
namespace for all available custom type convert classes) So, for our example we inherit from System.ComponentModel.StringConverter
Public Class StatesList : Inherits System.ComponentModel.StringConverter
Override the GetStandardValuesSupported
method to indicate that this object supports a standard set of values.
Public Overloads Overrides Function _
GetStandardValues(ByVal context As _
System.ComponentModel.ITypeDescriptorContext) _
As System.ComponentModel.TypeConverter.StandardValuesCollection
Return New StandardValuesCollection(_States)
End Function
Override the GetStandardValues
method and return a StandardValuesCollection
filled with our custom list.
Dim _States As String() = New String() {"Alabama", "Alaska",_
"Arizona", "Arkansas", _
"California", "Colorado", "Connecticut", "Delaware",_
"Florida", "Georgia", _
"Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", _
"Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", _
"Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", _
"Nebraska", "Nevada", "New Hampshire", _
"New Jersey", "New Mexico", _
"New York", "North Carolina", "North Dakota",_
"Ohio", "Oklahoma", _
"Oregon", "Pennsylvania", "Rhode Island", "South Carolina", _
"South Dakota", "Tennessee", "Texas", "Utah",_
"Vermont", "Virginia",_
"Washington", "West Virginia", "Wisconsin", "Wyoming"}
Public Overloads Overrides Function _
GetStandardValues(ByVal context As _
System.ComponentModel.ITypeDescriptorContext) _
As System.ComponentModel.TypeConverter.StandardValuesCollection
Return New StandardValuesCollection(_States)
End Function
Finally override the GetStandardValuesExclusive
method. When set to false
, it changes the dropdown list to Combo box (editable). If set to true
, then its a simple list box (Read only).
Public Overloads Overrides Function _
GetStandardValuesExclusive(ByVal context _
As System.ComponentModel.ITypeDescriptorContext) _
As Boolean
Return True
End Function
Then apply the statesList
class to the property by using the TypeConverterAttribute
. Let's add a State
property to the above example.
Private _State As String
<TypeConverter(GetType(StatesList)), _
CategoryAttribute("Custom List"), DefaultValueAttribute(""), _
DescriptionAttribute("Select a state from the list")> _
Public Property State() As String
Get
Return _State
End Get
Set(ByVal Value As String)
_State = Value
End Set
End Property
and here is the output.
Displaying custom data types with expandable properties
.NET framework data types like Size
, Point
when used in PropertyGrid
, they are rendered as collapsible list and displays the sub elements. Let's implement a custom data type that duplicates the above functionality. In order to display a custom data type with a collapsible list, we need a TypeConverter
, which converts an object type to string
type and back to object. Framework also provides an ExpandableObjectConverter
class (which is derived from TypeConverter
class ) under System.ComponentModel
namespace to implement this functionality. Create a class that defines your custom type. I am using Version number as custom type which will expand to Major,Minor,Build,Private parts.
Imports System.ComponentModel
Imports System.ComponentModel.Design.Serialization
<TypeConverter(GetType(ApplicationVersionConverter))> _
Public Class ApplicationVersion
Private _Major As Short
Private _Minor As Short
Private _Build As Short
Private _Private As Short
<DescriptionAttribute("Set the major part of version number")> _
Public Property Major() As Short
Get
Return _Major
End Get
Set(ByVal Value As Short)
_Major = Value
End Set
End Property
<DescriptionAttribute("Set the minor part of version number")> _
Public Property Minor() As Short
Get
Return _Minor
End Get
Set(ByVal Value As Short)
Me._Minor = Value
End Set
End Property
<DescriptionAttribute("Set the build part of version number")> _
Public Property Build() As Short
Get
Return _Build
End Get
Set(ByVal Value As Short)
Me._Build = Value
End Set
End Property
<DescriptionAttribute("Set the private part of version number")> _
Public Property [Private]() As Short
Get
Return _Private
End Get
Set(ByVal Value As Short)
Me._Private = Value
End Set
End Property
End Class
All the above code is like the other examples, except TypeConverter
attribute (<TypeConverter(GetType(ApplicationVersionConverter))>
) which points to the TypeConvert
class, that is used to convert our object to string
and back to object. Let's implement the TypeConvert
class
Friend Class ApplicationVersionConverter : Inherits ExpandableObjectConverter
Override the CanConvertTo
function to indicate whether this converter can convert the object to the specified type.
Public Overloads Overrides Function _
CanConvertTo(ByVal context As _
System.ComponentModel.ITypeDescriptorContext, _
ByVal destinationType As System.Type) As Boolean
If (destinationType Is GetType(ApplicationVersion)) Then
Return True
End If
Return MyBase.CanConvertFrom(context, destinationType)
End Function
Override the CanConvertFrom
function to indicate whether this converter can convert an object of one type to the type of this converter (in out case string to ApplicationVersion
).
Public Overloads Overrides Function _
CanConvertFrom(ByVal context As _
System.ComponentModel.ITypeDescriptorContext,_
ByVal sourceType As System.Type) As Boolean
If (sourceType Is GetType(String)) Then
Return True
End If
Return MyBase.CanConvertFrom(context, sourceType)
End Function
Override the ConvertFrom
method to implement the logic to convert the string
value to object
. While converting make sure that the value parameter is a String
.
Public Overloads Overrides Function _
ConvertFrom(ByVal context As _
System.ComponentModel.ITypeDescriptorContext, _
ByVal culture As System.Globalization.CultureInfo, _
ByVal value As Object) As Object
If TypeOf value Is String Then
Try
Dim s As String = CType(value, String)
Dim versionParts() As String
Dim VersionString As String = ""
versionParts = Split(s, ".")
If Not IsNothing(versionParts) Then
Dim _ApplicationVersion As _
ApplicationVersion = New ApplicationVersion()
If Not IsNothing(versionParts(0)) Then
_ApplicationVersion.Major = versionParts(0)
If Not IsNothing(versionParts(1)) Then
_ApplicationVersion.Minor = versionParts(1)
If Not IsNothing(versionParts(2)) Then
_ApplicationVersion.Build = versionParts(2)
If Not IsNothing(versionParts(3)) Then
_ApplicationVersion.Private = versionParts(3)
End If
Catch ex As Exception
Throw New ArgumentException("Can not convert '" + _
value + "' to type ApplicationVersion")
End Try
End If
Return MyBase.ConvertFrom(context, culture, value)
End Function
Override the ConvertTo
method to implement the logic to convert your object back to string
in a format you like. This is the value that is displayed for the parent. While converting make sure that the destinationType
parameter is a String
and that the value is the same type as the class.
Public Overloads Overrides Function
ConvertTo(ByVal context As _
System.ComponentModel.ITypeDescriptorContext, _
ByVal culture As System.Globalization.CultureInfo, _
ByVal value As Object, ByVal _
destinationType As System.Type) As Object
If (destinationType Is GetType(System.String) AndAlso _
TypeOf value Is ApplicationVersion) Then
Dim _ApplicationVersion As _
ApplicationVersion = CType(value, ApplicationVersion)
Return _ApplicationVersion.Major & "."_
& _ApplicationVersion.Minor & "." & _
_ApplicationVersion.Build & "." _
& _ApplicationVersion.Private
End If
Return MyBase.ConvertTo(context, culture, value, destinationType)
End Function
and here is the final output for this article.
In the source code I have a much elaborated example, which mimic's the SQLConnectsting
property.
Notes & To-Do features
In the next article I will explain about using custom editors to display properties like the docking, Graphics and tabs.
Working as consultant in Client/server,Web Development, Automation areas using C#,Vb,Vb.net,Asp.net,Sql Server,Xml,Html&Dhtml etc..
Looking for a challenging project in .NET