Simos Sigma
Simos Sigma

Reputation: 978

Add DesignerVerb on UserControl's Properties

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?

enter image description here

Upvotes: 2

Views: 1219

Answers (2)

TnTinMn
TnTinMn

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

Simos Sigma
Simos Sigma

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.

enter image description here enter image description here

Upvotes: 3

Related Questions