【问题标题】:Add DesignerVerb on UserControl's Properties在 UserControl 的属性上添加 DesignerVerb
【发布时间】:2018-04-02 13:13:30
【问题描述】:

编辑:找到我真正想要的东西后,我编辑了最初的问题,以便更好地描述我最终想要做的事情。

我正在开发一个UserControl,我想在它的属性上放置一个DesignerVerb,就像TreeView 控件一样。我怎样才能做到这一点?有可能吗?

【问题讨论】:

  • 根据您的一系列问题,似乎是在尝试学习Winform控件设计。您可能会在 this answer 中找到有用的资源列表。
  • 天哪,有这么多新东西要学……当然,如果我能先理解它们!!!谢谢你们两个有趣的链接!!!

标签: vb.net user-controls visual-studio-2017


【解决方案1】:

您不一定需要创建自定义设计器来访问 WinForm 设计环境公开的各种设计器服务。您只需要一个IServiceProvider Interface 的实例。所有具有System.ComponentModel.Component 的类都暴露Site Property。 Site 属性是一个 ISite 类型的实例,它本身继承自 IServiceProvider。

大部分设计服务由System.ComponentModel.Design Namespace 中记录的接口定义。像BehaviorService Class 这样的其他人被埋在文档中,必须专门寻找。

使用适当的设计器类有其优势,它可以自动集成到设计模型中并封装该功能。下面显示的技术的缺点是需要知道可以访问服务的适当时间。第一个时间标准是主机设计者已经完成加载。这是通过使用主机的 IsLoaded 属性和 LoadComplete 事件的组合来实现的。第二个是知道主机何时完成将组件添加到设计图面。场地属性的设置是设计交易的一部分。此事务完成后,可以访问组件的设计器。为此,您使用主机的 TransactionClosed 事件。

如上所述,入口点是覆盖继承的站点属性,以便您可以访问服务提供商。此示例获得对设计器宿主、其选择服务和控件默认设计器的引用。默认设计器允许您将DesignerVerb 添加到其动词集合中。

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

【讨论】:

    【解决方案2】:

    嗯,这是一个简单的例子……

    1.如果我们还没有这样做,我们应该添加一个referenceSystem.Design。转到Reference Manager &gt; Assemblies &gt; Framework 并找到System.Design。检查它并单击确定

    2. 在我们的 UserControl 代码中,我们确保我们已经有 Imports System.ComponentModelImports System.ComponentModel.Design 引用。

    3. 在我们的UserControl 类之上,我们添加一个Designer 属性,为这个UserControl 指定我们的ControlDesigner

    Imports System.ComponentModel
    Imports System.ComponentModel.Design
    
    <Designer(GetType(MyControlDesigner))>
    Public Class UserControl1
        'Our UserControl code in here...
    End Class
    

    4. 在我们的UserControl 类下,我们创建一个名为“MyControlDesigner”的新类,它将是我们的ControlDesigner

    Public Class MyControlDesigner
    
    End Class
    

    5. 例如,现在让我们创建一个Verb,它将DockUndock 我们的UserControlParentForm 中。

    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.然后我们构建我们的项目并将UserControl 添加到我们的测试表单中。

    【讨论】:

    • 哇!,有人真正研究了这个话题,并在提供了一些方向后自己解决了问题。这些天来发现如此稀有的宝石。 :) 干得好!
    • 既然您已经知道如何使用定制设计师来完成这项工作,那么您想学习如何在没有定制设计师的情况下完成这项工作吗?
    猜你喜欢
    • 1970-01-01
    • 2014-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-20
    • 2014-04-04
    相关资源
    最近更新 更多