Introduction
For my last project, I looked at the PropertyGrid
control that has a very nice look and feel. Immediately, I noticed how difficult it was to use it. Looking over the Internet, I found lots of people wishing for something easier to use, like the TreeView
or the ListView
. So I started developing an extended version of the PropertyGrid
that includes an Item
collection.
Using the Code
The control is made of three basic classes:
- Class
CustomProperty
, that represents a single property.
- Class
CustomPropertyDescriptor
, that is used internally by the PropertyGrid
to retrieve property attributes.
- Class
CustomPropertyCollection
, that represents a collection of CustomProperty
s.
In the end, we have the control PropertyGridEx
that inherits from PropertyGrid
and exposes an Item
collection. To use the component, add it to the Toolbox and then to your form. Compared to the classic PropertyGrid
, we have a new property to set, called ShowCustomProperties
.
The property must be set to True
, or the component will have the same behavior as the classic PropertyGrid
.
The Item Collection
We are now ready to fill our custom properties.
With Properties
.Item.Clear()
.Item.Add("My String", "My Value", False, _
"Simple type", "This is a string", True)
.Item.Add("My Integer", 100, False, "Simple type", _
"This is an integer", True)
.Item.Add("My Double", 10.4, False, "Simple type", _
"This is a double", True)
.Item.Add("My Font", New Font("Arial", 9), False, _
"Classes", "This is a font class", True)
.Item.Add("My Color", New Color(), False, _
"Classes", "This is a color class", True)
.Item.Add("My Point", New Point(10, 10), False, _
"Classes", "This is point class", True)
.Refresh()
End With
The CustomProperty
class exposes several properties that you can use to personalize your PropertyGrid
:
Name
, a string representing the property name;
Value
, an object representing the value of the property;
IsReadOnly
, a boolean that indicates if the property is editable or not;
Category
, a string that represents the category in which the property is shown;
Description
, a string that represents the description of the property, shown at the bottom of the component;
Visible
, a boolean that indicates if the property is shown or not;
Finally, remember to Refresh
the PropertyGrid
after any modification to the collection.
The Filename Editor
It is also possible to create a CustomProperty
that shows a dialog to modify a filename. The trick is achieved by the class UIFilenameEditor
that inherits from System.Drawing.Design.UITypeEditor
. You can create a property, with the well known FileDialog
as a Type Editor, in the following way:
With Properties
.Clear
.Item.Add("Filename", "", False, "Misc", "", True)
.Item(.Item.Count - 1).UseFileNameEditor = True
.Item(.Item.Count - 1).FileNameDialogType _
= FileDialogType.LoadFileDialog
.Item(.Item.Count - 1).FileNameFilter = _
"Text files (*.txt)|*.txt|All files (*.*)|*.*"
.Refresh()
End With
Following is the resulting PropertyGrid
. Please notice the Ellipsis symbol beside the value of the property, to access the UIFilenameEditor
.
Custom Choices Type Converter
It's a very commonly requested feature to have a list of values from which the user can choose, while editing a property. To implement a dropdown list, do the following:
Dim Languages As String() = New String() {"English", _
"Italian", _
"Spanish", _
"Dutch"}
With Properties
.Clear
.Item.Add("Language", "", False, "Misc", "")
.Item(.Item.Count - 1).Choices _
= New CustomChoices(Languages, True)
.Refresh()
End With
You can use arrays of String
, Integer
, Double
and Object
to initialize the Choices
property. Following is the resulting PropertyGrid
initialized with an array of String
s.
Enumerations
Most of the times, developers have enumerations declared in their code. The component automatically shows a dropdown list with the values from the Enum
.
Public Enum MyEnum
FirstEntry
SecondEntry
ThirdEntry
End Enum
With Properties
.Clear
.Item.Add("Enum", MyEnum.FirstEntry, False, "Misc")
.Refresh()
End With
Following is the resulting PropertyGrid
.
Expandable Object Converter
Using this TypeConverter
, it is possible to expand nested properties. Here is an example that shows the application settings.
With Properties
.Clear
.Item.Add("My settings", My.MySettings.Default, False, "Misc")
.Item(.Item.Count - 1).IsBrowsable = True
.Item(.Item.Count - 1).BrowsableLabelStyle = _
BrowsableTypeConverter.LabelStyle.lsEllipsis
.Refresh()
End With
Following is the resulting PropertyGrid
.
Password fields
Using masked fields, it is possible to hide the value of a property. The result is produced by the attribute PasswordPropertyTextAttribute
, new to the .NET Framework v2.0. Here is an example on how to use it.
With Properties
.Clear
.Item.Add("My Password", "password", False)
.Item(.Item.Count - 1).IsPassword = True
.Refresh()
End With
Following is the resulting PropertyGrid
.
Dynamic property binding
Using PropertyGridEx
, it is possible to bind object properties to the component. This is done by a method of the collection that accepts a value argument by reference. In this way, it is possible to freely mix reference type and value type properties. The following example binds the AutosizeProperties
and the DrawFlatToolbar
property of the grid.
Any modification to the value of these properties is automatically reflected into the object they belong to.
With Properties
.Clear
.Item.Add("Autosize properties", Properties, "AutoSizeProperties", False, _
"Dynamic Properties", "This is a dynamic bound property", True)
.Item.Add("Draw flat toolbar", Properties, "DrawFlatToolbar", False, _
"Dynamic Properties", "This is a dynamic bound property", True)
.Refresh()
End With
Following is the resulting PropertyGrid
.
Multiple object properties
One more feature provided with this control is the ability of editing multiple object properties at the same time. This is done by a collection of objects attached to the SelectedObjects
property of the base component. The behavior is that the grid only displays the properties that are common to all the objects that are in the array. To activate the multiple objects functionality, the property of the grid ShowCustomPropertiesSet
must be set to True
.
With Properties
.ShowCustomPropertiesSet = True
.ItemSet.Clear()
.ItemSet.Add()
.ItemSet(0).Add("My Point", New Point(10, 10), False, "Appearance")
.ItemSet(0).Add("My Date", New Date(2006, 1, 1), False, "Appearance")
.ItemSet.Add()
.ItemSet(1).Add("My Point", New Point(10, 10), False, "Appearance")
.ItemSet(1).Add("My Date", New Date(2007, 1, 1), False, "Appearance")
.ItemSet(1).Add("My Color", New Color(), False, "Appearance")
.Refresh()
End With
Following is the resulting PropertyGrid
.
Databinding of a Property to a Datasource
The databinding of a single property to a data-source is the latest addition to this component. The wrapper created accepts for a CustomProperty
, three members:
Datasource
, the datasource to bind to.
DisplayMember
(optional), the field used to bind the list shown in the dropdown control.
ValueMember
(optional), the field used to bind the value returned by the CustomProperty
.
The
CustomProperty
will return the following values:
Value
, that represents the value shown as System.String
.
SelectedItem
, that represents the object selected as System.Object
.
SelectedValue
, that represents the value selected as System.Object
.
The following example creates three properties that bind a
DataTable
, an array of
Object
s, and an array of
String
s.
With Properties
.Item.Clear()
.Item.Add("Datatable", "", False, "Databinding", _
"This is a UITypeEditor that implement a listbox", True)
.Item(.Item.Count - 1).ValueMember = "book_Id"
.Item(.Item.Count - 1).DisplayMember = "title"
.Item(.Item.Count - 1).Datasource = LookupTable
.Item.Add("Array of objects", ListValues(2).Text, False, "Databinding", _
"This is a UITypeEditor that implement a listbox", True)
.Item(.Item.Count - 1).ValueMember = "Value"
.Item(.Item.Count - 1).DisplayMember = "Text"
.Item(.Item.Count - 1).Datasource = ListValues
.Item.Add("Array of strings", Languages(1), False, "Databinding", _
"This is a UITypeEditor that implement a listbox", True)
.Item(.Item.Count - 1).Datasource = Languages
.Refresh()
End With
Please notice that the result is very different from the one achieved by using the "Custom Choices" functionality, that uses a TypeConverter
. The databinding feature uses a UITypeConverter
that implements a ListBox
control.
Following is the resulting PropertyGrid
.
Custom Event Editor
Using PropertyGridEx
, it is possible to bind the 3-dots button used in Modal editors with a custom event handler. This is done by a method of the CustomProperty
that accepts a Delegate
as argument. The following is an example:
With Properties
.Clear
.Item.Add("My Custom Event", "(Click me)", False, "Misc", _
"The component accept custom event handler.", True)
.Item(.Item.Count - 1).OnClick = AddressOf Me.CustomEventItem_OnClick
.Refresh()
End With
The event will be handled by this function:
Private Function CustomEventItem_OnClick(ByVal sender As Object, _
ByVal e As EventArgs) As Object
MsgBox("You clicked on property '" & sender.CustomProperty.Name & "'", _
MsgBoxStyle.Information, _
"Custom Events as UITypeEditor")
Return "(Click me again)"
End Function
Please notice that the result value of the function will be the new value of the property. Following is the resulting PropertyGrid
.
Add some style to the control
Looking on Internet and on CodeProject, I found a lot of articles regarding this component. Unfortunately, I had to merge everything together to have an easier PropertyGrid
to use. In this section, you'll find small features I've found and added in this project.
AutoSizeProperties
- Move automatically the splitter to better fit all the properties shown.
MoveSplitterTo
- Move the splitter as indicated by the user in the parameter.
DocComment
- Expose the comments area as a control.
DrawFlatToolbar
- Draw a flat toolbar or a VS like toolbar.
Please notice that the last property switches the drawing of the toolbar within a Professional Renderer with custom colors and a System Renderer.
Final Notes
I hope that you find this article useful. If you found this article stupid, annoying, incorrect, etc., express this fact by rating the article as you see fit.
Credits
Thanks to Pascal Higelin for providing the Property Binding feature and the C# version.
Thanks to Suresh Kavan, for the idea and the test case for the data-binding feature.
References
History
- 22nd August 2006
- 31st May 2006
- Added custom event editor.
- Added DocComment interface.
- 5th May 2006
- Added serialization.
- Added property databinding.
- Article updated.
- 28th April 2006
- Added C# version.
- Added dynamic property binding.
- Added multiple objects feature.
- 10th April 2006
- Added password property and improved ToolStrip look.
- Added expandable object converter.
- Added custom choices type converter.
- Added file name editor.
- 31st March 2006 – First submission.