【问题标题】:Adding a Form as a property to a user control with Designer support将表单作为属性添加到具有设计器支持的用户控件
【发布时间】:2019-10-14 10:07:24
【问题描述】:

我创建了一个自定义标签。它有一个Form 类型的属性,用户可以在设计器中选择表单,然后在单击标签时加载该表单。它工作正常,但属性下拉列表中的唯一形式是标签所在的形式。

有没有办法显示所有可能的表单,或者让用户将表单作为字符串传递,然后将其转换为表单。

这是我的标签的代码:


Public Class BMLabel
    Private t As String
    Private id As String
    Private frm As New Form

    <Category("BM")>
    Public Property Type As String
        Get
            Return t
        End Get
        Set(value As String)
            t = value
        End Set
    End Property

    Public Property Identifier As String
        Get
            Return id
        End Get
        Set(value As String)
            id = value
        End Set
    End Property

    Public Property Form As Form
        Get
            Return frm
        End Get
        Set(value As Form)
            frm = value
        End Set
    End Property

    Private Sub BMLabel_Click(sender As Object, e As EventArgs) Handles Me.Click
        Dim t = frm.GetType()

        Dim form As Form = DirectCast(Activator.CreateInstance(t), Form)
        form.ShowDialog()
    End Sub
End Class

【问题讨论】:

  • 旁注:您的所有属性似乎都没有任何附加逻辑,因此应转换为auto properties。这将使您的代码更易于阅读,并且不需要显式的支持字段。

标签: .net vb.net winforms windows-forms-designer


【解决方案1】:

问题是当你声明一个Form类型的属性时,它允许你选择一个表单实例,而不是一个继承自Form类型/类时间>。您需要做的是声明Type 类型的属性并准备允许您选择所需类型的编辑器(将选项限制为从Form 继承的类型)。

免责声明:创建自定义编辑器的想法受到this answer 的启发,代码针对这种特殊情况进行了调整。

那么,我们开始吧。自定义标签类看起来像这样:

Public Class BMLabel
    Inherits Label
    ' Don't forget to change the namespace.
    '        ↓↓↓↓↓↓↓↓↓↓↓
    <Editor("WindowsApp1.TypeSelector, System.Design", GetType(UITypeEditor)), Localizable(True)>
    Public Property FormType As Type

    Private Sub BMLabel_Click(sender As Object, e As EventArgs) Handles Me.Click
        Using frm As Form = DirectCast(Activator.CreateInstance(FormType), Form)
            frm.ShowDialog(Me)
        End Using
    End Sub
End Class

现在,我们需要创建TypeSelector 类:

Public Class TypeSelector
    Inherits UITypeEditor

    Public Overrides Function GetEditStyle(context As ITypeDescriptorContext) As UITypeEditorEditStyle
        If context Is Nothing OrElse context.Instance Is Nothing Then
            Return MyBase.GetEditStyle(context)
        End If

        Return UITypeEditorEditStyle.Modal
    End Function

    Public Overrides Function EditValue(context As ITypeDescriptorContext, provider As IServiceProvider, value As Object) As Object
        Dim editorService As IWindowsFormsEditorService

        If context Is Nothing OrElse context.Instance Is Nothing OrElse provider Is Nothing Then
            Return value
        End If

        editorService = DirectCast(provider.GetService(GetType(IWindowsFormsEditorService)),
                                   IWindowsFormsEditorService)

        Dim dlg As New FormTypeSelector()
        dlg.Value = DirectCast(value, Type)
        dlg.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
        If editorService.ShowDialog(dlg) = System.Windows.Forms.DialogResult.OK Then
            Return dlg.Value
        End If
        Return value
    End Function
End Class

然后,我们创建一个名为FormTypeSelector 的表单,其中包含ComboBoxListBox 以列出可用选项:

Public Class FormTypeSelector
    Friend Property Value As Type

    Private Sub FormTypeSelector_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim availableFormTypes =
            System.Reflection.Assembly.GetExecutingAssembly().
                    GetTypes().
                    Where(Function(t) t.BaseType = GetType(Form) AndAlso t <> Me.GetType()).ToList()
        cboFormTypes.DisplayMember = "Name"
        cboFormTypes.DataSource = availableFormTypes
        cboFormTypes.SelectedItem = Value
    End Sub

    Private Sub BtnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click
        Value = DirectCast(cboFormTypes.SelectedItem, Type)
        DialogResult = DialogResult.OK
        Close()
    End Sub

    Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
        DialogResult = DialogResult.Cancel
        Close()
    End Sub
End Class

就是这样;它应该准备好了:

注意:您可能需要在FormTypeSelector 中添加一个选项,以允许清除FormType 属性的选定值,这应该很容易做到。

【讨论】:

    【解决方案2】:

    有两种服务可以帮助您在设计时发现和解决解决方案中的所有类型:

    另一方面,要在属性编辑器的下拉列表中显示标准值,您可以创建一个TypeConverter

    • TypeConverter提供一种将值类型转换为其他类型以及访问标准值和子属性的统一方法。

    了解上述选项后,您可以创建自定义类型转换器以发现项目中的所有表单类型并在下拉列表中列出。

    示例

    在下面的示例中,我创建了一个自定义按钮类,它允许您在设计类型中选择一个表单类型,然后在运行时,如果您单击该按钮,它会将所选表单显示为对话框:

    要查看此答案的 C# 版本,请参阅 this post

    我的按钮

    Imports System.ComponentModel
    Public Class MyButton
        Inherits Button
        <TypeConverter(GetType(FormTypeConverter))>
        Public Property Form As Type
        Protected Overrides Sub OnClick(ByVal e As EventArgs)
            MyBase.OnClick(e)
            If Form IsNot Nothing AndAlso GetType(Form).IsAssignableFrom(Form) Then
    
                Using f = CType(Activator.CreateInstance(Form), Form)
                    f.ShowDialog()
                End Using
            End If
        End Sub
    End Class
    

    FormTypeConverter

    Imports System.ComponentModel
    Imports System.ComponentModel.Design
    Imports System.Globalization
    
    Public Class FormTypeConverter
        Inherits TypeConverter
        Public Overrides Function GetStandardValuesExclusive(ByVal context As ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function CanConvertTo(ByVal pContext As ITypeDescriptorContext, ByVal pDestinationType As Type) As Boolean
            Return MyBase.CanConvertTo(pContext, pDestinationType)
        End Function
        Public Overrides Function ConvertTo(ByVal pContext As ITypeDescriptorContext, ByVal pCulture As CultureInfo, ByVal pValue As Object, ByVal pDestinationType As Type) As Object
            Return MyBase.ConvertTo(pContext, pCulture, pValue, pDestinationType)
        End Function
        Public Overrides Function CanConvertFrom(ByVal pContext As ITypeDescriptorContext, ByVal pSourceType As Type) As Boolean
            If pSourceType = GetType(String) Then Return True
            Return MyBase.CanConvertFrom(pContext, pSourceType)
        End Function
        Public Overrides Function ConvertFrom(ByVal pContext As ITypeDescriptorContext, ByVal pCulture As CultureInfo, ByVal pValue As Object) As Object
            If TypeOf pValue Is String Then Return GetTypeFromName(pContext, CStr(pValue))
            Return MyBase.ConvertFrom(pContext, pCulture, pValue)
        End Function
        Public Overrides Function GetStandardValuesSupported(ByVal pContext As ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetStandardValues(ByVal pContext As ITypeDescriptorContext) As StandardValuesCollection
            Dim types As List(Of Type) = GetProjectTypes(pContext)
            Dim values As List(Of String) = New List(Of String)()
            For Each type As Type In types
                values.Add(type.FullName)
            Next
            values.Sort()
            Return New StandardValuesCollection(values)
        End Function
        Private Function GetProjectTypes(ByVal serviceProvider As IServiceProvider) As List(Of Type)
            Dim typeDiscoverySvc = CType(serviceProvider.GetService(GetType(ITypeDiscoveryService)), ITypeDiscoveryService)
            Dim types = typeDiscoverySvc.GetTypes(GetType(Object), True).Cast(Of Type)().Where(Function(item) item.IsPublic AndAlso GetType(Form).IsAssignableFrom(item) AndAlso Not item.FullName.StartsWith("System")).ToList()
            Return types
        End Function
        Private Function GetTypeFromName(ByVal serviceProvider As IServiceProvider, ByVal typeName As String) As Type
            Dim typeResolutionSvc As ITypeResolutionService = CType(serviceProvider.GetService(GetType(ITypeResolutionService)), ITypeResolutionService)
            Return typeResolutionSvc.[GetType](typeName)
        End Function
    End Class
    

    【讨论】:

      猜你喜欢
      • 2022-01-18
      • 1970-01-01
      • 2010-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-02
      相关资源
      最近更新 更多