Reputation: 978
EDIT: After I found what I was really looking for, I edited my initial question so to describe better what I finaly wanted to do.
I am working on a UserControl
and I want to place a DesignerVerb
at it's properties, like TreeView
control have. How can I do this? Is it possible?
Upvotes: 2
Views: 1219
Reputation: 11801
You do not necessarily need to create a custom designer to access the various designer services exposed by the WinForm design environment. All you need is an instance of a IServiceProvider Interface. All classes that have System.ComponentModel.Component in their ancestry expose the Site Property. The Site Property is an instance of type ISite that itself inherits from IServiceProvider.
Most of the design services are defined by the interfaces documented in the System.ComponentModel.Design Namespace. Others like the BehaviorService Class are buried in the documentation and have to be specifically sought out.
Using a proper designer class has its advantages in that it automatically integrates into the design model and encapsulates that functionality. The technique shown below has the drawback of needing to know the proper time that services are accessible. The first temporal criteria is that the host designer has finished loading. This is achieved by using a combination the host's IsLoaded property and LoadComplete events. The second is knowing when the host is finished adding your component to the design surface. The setting of the Site Property is part of design transaction. When this transaction is completed, the component's designer is accessible. For this, you use the host's TransactionClosed Event.
With that stated, the entry point is to override the inherited Site Property so that you can gain access to the service provider. This example gains references to the designer host, its selection service, and the controls default designer. The default designer allows you to add a DesignerVerb to its Verb collection.
Imports System.ComponentModel
Imports System.ComponentModel.Design
Public Class DemoControl : Inherits Control
Public Sub New()
MyBase.New()
BackColor = Color.Red ' just so we can see it
End Sub
#Region "Designer Services"
Private designerHost As Design.IDesignerHost
Private myDesigner As Design.IDesigner
Private designerSelectionService As Design.ISelectionService
Private Shared customDesignerVerb1 As Design.DesignerVerb
Public Overrides Property Site As ISite
Get
Return MyBase.Site
End Get
Set(value As ISite)
MyBase.Site = value
If value Is Nothing Then ' being removed from the design surface
DetachDesignerServices()
Else ' being added to the design surface
designerHost = CType(value.GetService(GetType(Design.IDesignerHost)), Design.IDesignerHost)
If designerHost IsNot Nothing Then
If designerHost.Loading Then
' the designer has not finished loading,
' postpone all other connections until it has finished loading
AddHandler designerHost.LoadComplete, AddressOf DesignerHostLoaded
Else
' designerHost loaded, but is in the in the process of creating this instance
If designerHost.InTransaction Then
AddHandler designerHost.TransactionClosed, AddressOf DesignerTransactionClosed
Else
AttachDesignerServices()
End If
End If
End If
End If
End Set
End Property
Private Sub DesignerHostLoaded(sender As Object, e As EventArgs)
RemoveHandler designerHost.LoadComplete, AddressOf DesignerHostLoaded
AttachDesignerServices()
End Sub
Private Sub DesignerTransactionClosed(sender As Object, e As DesignerTransactionCloseEventArgs)
RemoveHandler designerHost.TransactionClosed, AddressOf DesignerTransactionClosed
AttachDesignerServices()
End Sub
Private Sub AttachDesignerServices()
myDesigner = designerHost.GetDesigner(Me)
If customDesignerVerb1 Is Nothing Then
customDesignerVerb1 = New Design.DesignerVerb("Verb1", AddressOf DesignerVerb1EventHandler)
End If
If myDesigner IsNot Nothing AndAlso
Not myDesigner.Verbs.Contains(customDesignerVerb1) Then
myDesigner.Verbs.Add(customDesignerVerb1)
End If
designerSelectionService = CType(designerHost.GetService(GetType(Design.ISelectionService)), Design.ISelectionService)
If designerSelectionService IsNot Nothing Then
AddHandler designerSelectionService.SelectionChanged, AddressOf DesignerSelectionChanged
End If
End Sub
Private Sub DetachDesignerServices()
If designerSelectionService IsNot Nothing Then
RemoveHandler designerSelectionService.SelectionChanged, AddressOf DesignerSelectionChanged
designerSelectionService = Nothing
End If
If designerHost IsNot Nothing Then
RemoveHandler designerHost.LoadComplete, AddressOf DesignerHostLoaded
designerHost = Nothing
End If
If myDesigner IsNot Nothing Then
myDesigner = Nothing
End If
End Sub
Private Sub DesignerSelectionChanged(sender As Object, e As EventArgs)
Static shownCount As Int32
If designerSelectionService.GetComponentSelected(Me) AndAlso shownCount < 2 Then
MessageBox.Show("I've been selected." & If(shownCount = 0, " This will show one more time on selecting.", ""))
shownCount += 1
End If
End Sub
Private Sub DesignerVerb1EventHandler(sender As Object, e As EventArgs)
MessageBox.Show("Verb1 Cicked")
End Sub
#End Region ' "Designer Services
End Class
Upvotes: 3
Reputation: 978
Well, here is a simple example...
1. If we haven't done already, we should add a reference to System.Design. Goto Reference Manager > Assemblies > Framework
and find System.Design
. Check it and click OK.
2. Into our UserControl
code, we make sure that we already have Imports System.ComponentModel
and Imports System.ComponentModel.Design
references.
3. Over our UserControl
class, we add a Designer
attribute, to specify our ControlDesigner
for this UserControl
.
Imports System.ComponentModel
Imports System.ComponentModel.Design
<Designer(GetType(MyControlDesigner))>
Public Class UserControl1
'Our UserControl code in here...
End Class
4. Under our UserControl
class, we create a new class by the name "MyControlDesigner" which will be our ControlDesigner
.
Public Class MyControlDesigner
End Class
5. Now, for example, lets create a Verb
which will Dock
and Undock
our UserControl
in ParentForm
.
Public Class MyControlDesigner
Inherits System.Windows.Forms.Design.ControlDesigner 'Inherit from ControlDesigner class.
Private MyVerbs As DesignerVerbCollection
Public Sub New()
End Sub
Public Overrides ReadOnly Property Verbs() As DesignerVerbCollection
Get
If MyVerbs Is Nothing Then
MyVerbs = New DesignerVerbCollection 'A new DesignerVerbCollection to use for our DesignerVerbs.
MyVerbs.Add(New DesignerVerb("Dock In ParentForm", New EventHandler(AddressOf OnMyCommandLinkClicked))) 'An Event Handler for Docking our UserControl.
MyVerbs.Add(New DesignerVerb("Undock in ParentForm", New EventHandler(AddressOf OnMyCommandLinkClicked))) 'An Event Handler for Undocking our UserControl.
MyVerbs(1).Visible = False 'We hide second Verd by default.
End If
Return MyVerbs
End Get
End Property
Private Sub OnMyCommandLinkClicked(ByVal sender As Object, ByVal args As EventArgs)
Dim _UserControl As UserControl1 = CType(Me.Control, UserControl1) 'Reference to our UserControl1 Class, so we can access it's Properties and Methods.
If _UserControl.Dock = DockStyle.None Then 'If UserControl is Undocked then...
_UserControl.Dock = DockStyle.Fill 'Dock UserControl in ParentForm.
MyVerbs(0).Visible = False 'Hide "Dock In ParentForm" DesignerVerb.
MyVerbs(1).Visible = True 'Show "Undock in ParentForm" DesignerVerb.
Else
_UserControl.Dock = DockStyle.None 'Undock UserControl.
MyVerbs(1).Visible = False 'Hide "Undock in ParentForm" DesignerVerb.
MyVerbs(0).Visible = True 'Show "Dock in ParentForm" DesignerVerb.
End If
End Sub
End Class
6. Then we Build our project and we add our UserControl
into our test Form.
Upvotes: 3