Introduction
The point of the tip is about gaining access to the design time form from within a property editor (UITypeEditor
) in Visual Studio using Visual Basic.
Notes on the download
- Don't try running the app, it doesn't do anything
- The point is that within the IDE, with the form designer open (
Simple Demo
-> ExampleForm
), you can select the component called ExampleComponent1
and then in the property editor, the TargetControls
property is a collection and clicking on the ellipsis reveals the UITypeEditor
- You can note that the controls that are selected (or not) are persisted between IDE sessions which means that when you build your app, the collection will be visible at run time
I was creating a Visual Studio property editor (UITypeEditor
) for a .NET component
that holds a subset of the controls
on the form
to which it is attached at design time. Initially, I had great difficulty working out how to do that but as usual, once you discover the answer, it turns out to be pretty easy.
The image below shows a demo application using the custom UITypeEditor
. There's a custom component with a property, called TargetControls
, which uses that custom UITypeEditor
. The actual property editor itself is the form bottom left (red border) and as you can see, it contains a list of the controls
on the form shown at the top. The image is from within Visual Studio, not in debugging mode, so that's the form designer you can see at the top.
Background
It's pretty easy to create a Collection(Of Control)
at run-time, where the Controls
in the Collection
are the Controls
on the Form
. It's notably more difficult to do this at design time - and that's what I needed to do, so I created a UITypeEditor
that can populate a Component
or Control
property with one or more of the Controls
on a form at design time. I used the Creating Property Editors in DesignTime for VS.Net Easily (UITypeEditor Helper) article by S.Serpooshan to provide the base class.
Here, I will reproduce only the part of the code for retrieving the list of Controls on the form since the full class will (hopefully) be the subject of an article rather than a tip.
Using the Code
Within a UITypeEditor
, there is a method called EditValue
, whose job is to display the custom control (a dropdown or a modal form) and update the property dependent on how the user interacts with the control. I've removed all the surrounding code that loads and shows the custom control and the code that manages updating the property in order to focus the tip on the interesting bit. All the other stuff you can get from S. Serpooshan's article.
myControl
is a reference to the custom property editor control, which in this case is a form with a CheckedListBox
(the name of which is AvailableControls
).
The first For Each
loop adds items to that CheckedListBox
having accessed a reference to the design time form through the context
parameter of the EditValue
function. Working out that this parameter gives you a way to reference the design time form was the key, it's pretty easy from there.
The second For Each
loop simply determines which items in the CheckedListBox
to check before displaying it, i.e., those that are held in the current value of the property before the user gets a chance to edit it.
Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, _
ByVal provider As IServiceProvider, ByVal value As Object) As Object
...
...
For Each c As Component In context.Container.Components
If TypeOf c Is Control Then
myControl.AvailableControls.Items.Add(c)
End If
Next
If value IsNot Nothing Then
Dim tCollection As Collection(Of Control) = CType(value, Collection(Of Control))
Dim found As Integer
For Each c As Control In tCollection
found = myControl.AvailableControls.Items.IndexOf(c)
If Not found = -1 Then
myControl.AvailableControls.SetItemChecked(found, True)
End If
Next
End If
...
...
End Function
To use the code, you would create a custom component with a public
property of type Collection(Of Control)
. You'd then set its EditorAttribute
to the class name of the UITypeEditor
.
Public Class ControlCollectionUITypeEditor
Inherits UITypeEditor
...
...
End Class
Public Class ExampleComponent
Inherits Component
Private _TargetControls As New Collection(Of Control)
<EditorAttribute(GetType(ControlCollectionUITypeEditor), _
GetType(System.Drawing.Design.UITypeEditor))>
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
Public Property TargetControls As Collection(Of Control)
Get
Return _TargetControls
End Get
Set(ByVal value As Collection(Of Control))
_TargetControls = value
End Set
End Property
End Class
Points of Interest
I went around the houses on this with a couple of folks at the MSDN Visual Basic General forum, the main thrust of which is 'you can't do it'.
You can if you try hard enough!
History
- Version 1: Original tip
- Version 2: Added download per answer to question 29 October 2013