Добавление формы в качестве свойства в пользовательский элемент управления - PullRequest
2 голосов
/ 14 октября 2019

Я создал пользовательский ярлык. У него есть свойство типа 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

Ответы [ 2 ]

3 голосов
/ 15 октября 2019

Проблема в том, что когда вы объявляете свойство типа Form, оно позволяет вам выбрать экземпляр формы , а не тип / класс, который наследуется от Form,Вместо этого вам нужно объявить свойство типа Type и подготовить редактор, который позволит вам выбрать нужный тип (ограничивая параметры типами, которые наследуются от Form).

Отказ от ответственности: Идея создания пользовательского редактора была вдохновлена ​​ этим ответом , и код был адаптирован для этой конкретной ситуации.

Итак, поехали. Пользовательский класс метки будет выглядеть примерно так:

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с помощью ComboBox или ListBox для просмотра списка доступных опций:

FormTypeSelector

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

И это все;он должен быть готов к работе:

Demo

Примечание: вам, вероятно, потребуется добавить параметр в FormTypeSelector, чтобы разрешить очистку выбранного значениясвойство FormType, которое должно быть достаточно простым.

1 голос
/ 27 октября 2019

Существует две службы, которые могут помочь вам во время разработки обнаружить и разрешить все типы решений:

  • ITypeDiscoveryService: Обнаруживает доступные типы во время разработки.

  • ITypeResolutionService: Предоставляет интерфейс для извлечения сборки или типа по имени.

С другой стороны, чтобы показать стандартные значения в раскрывающемся списке в редакторе свойств, вы можете создать TypeConverter:

  • TypeConverter: Предоставляет унифицированный способ преобразования типов значений в другие типы, а также для доступа к стандартным значениям и подвойствам.

Зная о вышеописанных параметрах, вы можетесоздайте пользовательский конвертер типов, чтобы обнаружить все типы форм в проекте и список в раскрывающемся списке.

Пример

В следующем примере я создал пользовательский класс кнопок, который позволяет вам выбирать тип формы в типе дизайна, а затем во время выполнения,если вы нажмете на кнопку, в диалоговом окне отобразится выбранная форма:

enter image description here

Чтобы увидеть версию C # для этого ответа, см. этот пост .

MyButton

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...