Получите раскрывающийся список PropertyGrid из свойства, являющегося классом объекта, а не просто строкой - PullRequest
0 голосов
/ 20 марта 2020

Как мне получить свойства, которые являются объектами (а не просто строками), раскрывающимися в сетке свойств? Я так далеко, но потом застрял! Рассмотрим приведенный ниже код:

Public Class mOrganisation

    Public Property ID as String
    Public Property Name as String

End Class

Public Class mSystem

    Public Property ID as string
    Public Property Name as String
    Public Property Developer as mOrganisation

     Public Overrides Function ToString() As String
        Return Name
    End Function

End Class

Public Class mGame

    Public Property ID as string
    Public Property Name as String

    <TypeConverter(GetType(SystemConverter))>
    Public Property System as mSystem

End Class

Public Class Main

    Public Systems as List(of mSystem) = [...list gatehring code here]

End Class


Public Class SystemConverter
Inherits TypeConverter

    Public Overrides Function GetStandardValuesSupported(ByVal context As ITypeDescriptorContext) As Boolean
        Return True
    End Function

    Public Overrides Function GetStandardValuesExclusive(ByVal context As ITypeDescriptorContext) As Boolean
        Return False
    End Function

    Public Overrides Function GetStandardValues(ByVal context As ITypeDescriptorContext) As TypeConverter.StandardValuesCollection
        Return New StandardValuesCollection(Main.Systems)
    End Function

End Class

mOrgnisation - это просто введение в усложнение класса mSystem. Теперь этот код опускает значения:

enter image description here

Но когда я выбираю значение, я получаю ошибку PropertyGrid «Объект типа» System.String 'не может быть преобразован в тип' mSystem '"

Это привело меня к кроличьей норе, особенно пытаясь применить различные перестановки Convert From и Convert To. Однако я не смог найти достойного решения. Одна попытка через ConvertFrom заставляла выпадающее меню загружаться очень медленно, по одному элементу за раз (я думаю, что оно запускалось для каждого элемента).

Я бы сделал пользовательский UITypeEditor, но я не могу найти способ получить собственный метод / дескриптор изменения размера PropertyGrid, как в стандартном раскрывающемся списке (и попытался кодировать свою собственную процедуру изменения размера, но оказался липким и мерцательным Я думаю, из-за взаимодействия PropGrid + контроль)

Каков наилучший / самый элегантный способ достичь этого?

Ответы [ 2 ]

1 голос
/ 20 марта 2020

Есть несколько способов сообщить системе «Что выбрать из объекта»

1) Использовать DisplayMemberPath в ComboBox:

<ComboBox ItemsSource="{Binding Path=mSystem}" 
      DisplayMemberPath="Name"/>

2) Установить ItemTemplate в ComboBox. Это похоже на # 1, за исключением того, что позволяет определить шаблон для отображения:

<ComboBox ItemsSource="{Binding Path=mSystem}">
<ComboBox.ItemTemplate>
    <DataTemplate>
        <Border BorderBrush="Green" BorderThickness="1" Padding="5">
            <TextBlock Text="{Binding Path=Name,StringFormat='Name: {0}'}" />
        </Border>
    </DataTemplate>
</ComboBox.ItemTemplate>

3) Добавьте DataTemplate к ресурсам XAML. Это полезно для связывания данного класса:

<UserControl xmlns:local="CLASS_CONTEXT_HERE">
<UserControl.Resources>
    <DataTemplate DataType="local:mSystem">
        <TextBlock Text="{Binding Name}" />
    </DataTemplate>
</UserControl.Resources>

4) Если вы хотите отобразить NAME и ID:

Public Overrides Function ToString() As String
    Return string.Format("{0} ({1})", Name, ID)
End Function
0 голосов
/ 20 марта 2020

В конце концов отказался от TypeConverter и нашел решение. Как и большинство кошмаров кодирования, это были 5 простых строк, помещенных в нужное место! Ключом был доступ к встроенному дескриптору изменения размера PropertyGrid. Вы можете настроить код ниже, чтобы включить построение в обработку пользовательских объектов, так как value - любой объект. Однако для примера ниже приведена строка, для простоты:

Public Overrides ReadOnly Property IsDropDownResizable As Boolean
    Get
        Return True
    End Get
End Property

Вот как это сделать:

Шаг 1: Создайте новый UITypeEditor

Это связывает свойство с пользовательским редактором. значение содержит значение, переданное из свойства. Это может быть объект любого типа. Поэтому вы можете передать его в свой пользовательский элемент управления, чтобы сообщить в него любые функции редактирования.

Создайте новый класс:

Imports System.ComponentModel
Imports System.Drawing.Design
Imports System.Windows.Forms.Design

Public Class TestUIEditor
    Inherits UITypeEditor

    ' Indicate that we display a dropdown.
    Public Overrides Function GetEditStyle(ByVal context As ITypeDescriptorContext) _
        As UITypeEditorEditStyle

        Return UITypeEditorEditStyle.DropDown

    End Function

    Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, ByVal provider As IServiceProvider, ByVal value As Object) As Object

        ' Get an IWindowsFormsEditorService object.
        Dim editor_service As IWindowsFormsEditorService = CType(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
        If editor_service Is Nothing Then
            Return MyBase.EditValue(context, provider, value)
        End If

        'Setup the editor
        Dim editorService As IWindowsFormsEditorService = Nothing
        If provider IsNot Nothing Then
            editorService = TryCast(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
        End If

        If editorService IsNot Nothing Then

            Dim testUI As New TestPropGridUI(editorService)
            'Populate the existing value to the dropdown control
            testUI.Text = value
            'Drop down the control
            editorService.DropDownControl(testUI)
            'Update property value once dropdown closed
            value = testUI.Text

        End If

        Return value

    End Function

    Public Overrides ReadOnly Property IsDropDownResizable As Boolean
        Get
            'Ensures control is resizable
            Return True
        End Get
    End Property

End Class

Шаг 2: Создайте свой собственный редактор:

В этом примере я только что использовал пользовательский класс, который наследует TextBox. Однако вы можете использовать любые элементы управления, даже пользовательский UserControl.

Imports System.Windows.Forms.Design

Public Class TestPropGridUI
    Inherits TextBox

    ' The editor service displaying this control.
    Private m_EditorService As IWindowsFormsEditorService

    Public Sub New(ByVal editor_service As IWindowsFormsEditorService)
        MyBase.New()

        m_EditorService = editor_service
        Dock = DockStyle.Fill

    End Sub

    Public Sub returnPressed(sender As Object, e As KeyEventArgs) Handles Me.KeyDown

        'Closes the dropdown when Enter pressed
        If e.KeyCode = Keys.Enter Then
            m_EditorService.CloseDropDown()
        End If

    End Sub

End Class

Примечание m_EditorService.CloseDropDown. Поместите его туда, где вы хотите, чтобы раскрывающийся список закрывался сам (например, после выбора значения).

Шаг 3. Скажите свойству класса использовать пользовательский редактор:

Public Class TestObject

    Public Property ID as String
    Public Property Quantity as Integer

    <Editor(GetType(TestUIEditor), GetType(UITypeEditor))>
    Public Property TestText As String

End Class

И это все!

...