在 UserControl 的属性上添加 DesignerVerb
Add DesignerVerb on UserControl's Properties
编辑:在我找到我真正想要的东西之后,我编辑了我最初的问题,以便更好地描述我最终想做的事情。
我正在开发一个 UserControl
,我想在它的属性中放置一个 DesignerVerb
,就像 TreeView
控件一样。我怎样才能做到这一点?可能吗?
嗯,这是一个简单的例子...
1. 如果我们还没有完成,我们应该添加一个 reference 到 System.Design。转到 Reference Manager > Assemblies > Framework
并找到 System.Design
。检查它并单击确定。
2. 进入我们的 UserControl
代码,我们确保我们已经有 Imports System.ComponentModel
和 Imports System.ComponentModel.Design
引用。
3. 在我们的 UserControl
class 上,我们添加一个 Designer
属性,为此指定我们的 ControlDesigner
UserControl
.
Imports System.ComponentModel
Imports System.ComponentModel.Design
<Designer(GetType(MyControlDesigner))>
Public Class UserControl1
'Our UserControl code in here...
End Class
4. 在我们的 UserControl
class 下,我们创建一个名为 "MyControlDesigner" 的新 class,它将是我们的ControlDesigner
。
Public Class MyControlDesigner
End Class
5. 现在,例如,让我们创建一个 Verb
,它将 Dock
和 Undock
我们的 UserControl
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.然后我们构建我们的项目,我们将UserControl
添加到我们的测试表单中。
您不一定需要创建自定义设计器来访问 WinForm 设计环境公开的各种设计器服务。您只需要 IServiceProvider Interface. All classes that have System.ComponentModel.Component in their ancestry expose the Site Property 的一个实例。 Site 属性 是 ISite 类型的实例,它本身继承自 IServiceProvider。
大多数设计服务都是由System.ComponentModel.Design Namespace. Others like the BehaviorService Class中记录的接口定义的,这些接口被隐藏在文档中,必须专门寻找。
使用合适的设计器 class 有其优点,因为它可以自动集成到设计模型中并封装该功能。下面显示的技术的缺点是需要知道服务可访问的正确时间。第一个时间标准是主机设计者已完成加载。这是通过结合使用主机的 IsLoaded 属性 和 LoadComplete 事件来实现的。第二个是知道主机何时完成将您的组件添加到设计图面。站点 属性 的设置是设计交易的一部分。完成此事务后,即可访问组件的设计器。为此,您使用主机的 TransactionClosed 事件。
话虽如此,入口点是覆盖继承的站点 属性,以便您可以访问服务提供商。此示例获取对设计器宿主、其选择服务和控件默认设计器的引用。默认设计器允许您将 DesignerVerb 添加到其 Verb 集合。
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
编辑:在我找到我真正想要的东西之后,我编辑了我最初的问题,以便更好地描述我最终想做的事情。
我正在开发一个 UserControl
,我想在它的属性中放置一个 DesignerVerb
,就像 TreeView
控件一样。我怎样才能做到这一点?可能吗?
嗯,这是一个简单的例子...
1. 如果我们还没有完成,我们应该添加一个 reference 到 System.Design。转到 Reference Manager > Assemblies > Framework
并找到 System.Design
。检查它并单击确定。
2. 进入我们的 UserControl
代码,我们确保我们已经有 Imports System.ComponentModel
和 Imports System.ComponentModel.Design
引用。
3. 在我们的 UserControl
class 上,我们添加一个 Designer
属性,为此指定我们的 ControlDesigner
UserControl
.
Imports System.ComponentModel
Imports System.ComponentModel.Design
<Designer(GetType(MyControlDesigner))>
Public Class UserControl1
'Our UserControl code in here...
End Class
4. 在我们的 UserControl
class 下,我们创建一个名为 "MyControlDesigner" 的新 class,它将是我们的ControlDesigner
。
Public Class MyControlDesigner
End Class
5. 现在,例如,让我们创建一个 Verb
,它将 Dock
和 Undock
我们的 UserControl
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.然后我们构建我们的项目,我们将UserControl
添加到我们的测试表单中。
您不一定需要创建自定义设计器来访问 WinForm 设计环境公开的各种设计器服务。您只需要 IServiceProvider Interface. All classes that have System.ComponentModel.Component in their ancestry expose the Site Property 的一个实例。 Site 属性 是 ISite 类型的实例,它本身继承自 IServiceProvider。
大多数设计服务都是由System.ComponentModel.Design Namespace. Others like the BehaviorService Class中记录的接口定义的,这些接口被隐藏在文档中,必须专门寻找。
使用合适的设计器 class 有其优点,因为它可以自动集成到设计模型中并封装该功能。下面显示的技术的缺点是需要知道服务可访问的正确时间。第一个时间标准是主机设计者已完成加载。这是通过结合使用主机的 IsLoaded 属性 和 LoadComplete 事件来实现的。第二个是知道主机何时完成将您的组件添加到设计图面。站点 属性 的设置是设计交易的一部分。完成此事务后,即可访问组件的设计器。为此,您使用主机的 TransactionClosed 事件。
话虽如此,入口点是覆盖继承的站点 属性,以便您可以访问服务提供商。此示例获取对设计器宿主、其选择服务和控件默认设计器的引用。默认设计器允许您将 DesignerVerb 添加到其 Verb 集合。
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