Развернуть коллекцию в сетке свойств без каких-либо изменений в классе?

1

Этот подход работает для всего, кроме коллекций:

Коллекции отображаются следующим образом:

Изображение 174551

Поэтому, несмотря на то, что они расширяемы, для них внутри сети свойств мало пользы.

Вот пример того, что я ищу (снимок экрана отсюда):

Изображение 174551

Связанная статья также содержит некоторый код, который бы сделал это, но требует модификации исходного класса. Между этим и моим предыдущим вопросом я придумал некоторые идеи, но я не очень свободно говорю об использовании пространства имен System.ComponentModel.

Ниже приведен сниженный тестовый пример (пользовательский класс с одним свойством типа коллекции, который содержит один объект пользовательского типа, который имеет одно свойство строки):

Imports System.ComponentModel

Public Class Form1

  Sub New()
    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.
    Me.AssignTypeConverter(Of MyCustomClassCollection, ExpandableObjectConverter)()
  End Sub

  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    Dim collection As New MyCustomClassCollection
    collection.Add(New MyCustomClass With {.MyCustomProperty = "Hello"})

    Dim container As New MyCustomClassCollectionContainer(collection)

    Me.PropertyGrid1.SelectedObject = container
  End Sub

  Private Sub AssignTypeConverter(Of IType, IConverterType)()
    System.ComponentModel.TypeDescriptor.AddAttributes(GetType(IType),
      New System.ComponentModel.TypeConverterAttribute(GetType(IConverterType)))
  End Sub

End Class


Public Class MyCustomClass
  Public Property MyCustomProperty As String
End Class

Public Class MyCustomClassCollection : Inherits System.Collections.ObjectModel.Collection(Of MyCustomClass)
End Class

Public Class MyCustomClassCollectionContainer

  Dim _items As MyCustomClassCollection

  Public ReadOnly Property Items As MyCustomClassCollection
    Get
      Return _items
    End Get
  End Property

  Sub New(items As MyCustomClassCollection)
    _items = items
  End Sub

End Class

Предлагаемое решение (псевдокод, не компилируется)

Imports System.ComponentModel

Public Class MyCustomClassTypeDescriptor : Inherits ExpandableObjectConverter

  Public Overrides Function GetProperties(context As ITypeDescriptorContext,
                                value As Object, attributes() As Attribute) _
                                            As PropertyDescriptorCollection
    Dim pds As New PropertyDescriptorCollection(Nothing)
    Dim lst As IList(Of Object) = DirectCast(value, IList)
    For i As Integer = 0 To lst.Count - 1
      Dim item As MyCustomClass = DirectCast(lst.Item(i), MyCustomClass)
      'compile error - abstract class cannot be instantiated
      Dim pd As New PropertyDescriptor(item)
      pds.Add(pd)
    Next
    Return pds
  End Function

End Class

Затем примените этот настраиваемый конвертер объектов во время выполнения.

Будет ли это работать так? Что мне не хватает? Любые предложения приветствуются!

Примечание. Вышеупомянутый вариант - VB.NET, но если вы говорите на С#, не стесняйтесь его использовать.

  • 0
    Вы хотите добавить / удалить элементы в коллекции? если это так, вам понадобится CollectionEditor и несколько частей для обработки дизайнерской сериализации. Я не совсем уверен, чем вы занимаетесь, но вы также можете написать CollectionEditor и назначить его существующей коллекции, к которой у вас нет доступа, через: System.ComponentModel.TypeDescriptor.AddEditorTable
  • 0
    @ Plutonix: мне нужно только просматривать существующие элементы коллекции и иметь возможность редактировать их свойства. Мне не нужно добавлять новые или удалять элементы коллекции в сетке свойств. Не могли бы вы уточнить ваше предложение?
Показать ещё 11 комментариев
Теги:
propertygrid

1 ответ

1
Лучший ответ

Слишком долго продолжаться в комментариях, но как насчет чего-то вроде этого - настраиваемый ExpandableObjectConverter который превращает каждый элемент коллекции в свойство (ItemX) и дескриптор настраиваемого свойства, который получает соответствующий элемент.

Public Class MyCollectionTypeDescriptor(Of TColl As Collection(Of TItem), TItem)
    Inherits ExpandableObjectConverter

    Public Overrides Function GetProperties(context As ITypeDescriptorContext, value As Object, attributes() As Attribute) As PropertyDescriptorCollection
        Dim coll = DirectCast(value, TColl)
        Dim props(coll.Count - 1) As PropertyDescriptor
        For i = 0 To coll.Count - 1
            props(i) = New MyCollectionPropertyDescriptor(Of TColl, TItem)("Item" & CStr(i))
        Next
        Return New PropertyDescriptorCollection(props)
    End Function

End Class

Public Class MyCollectionPropertyDescriptor(Of TColl, TItem)
    Inherits PropertyDescriptor

    Private _index As Integer = 0

    Public Sub New(name As String)
        MyBase.New(name, Nothing)
        Dim indexStr = Regex.Match(name, "\d+$").Value
        _index = CInt(indexStr)
    End Sub

    Public Overrides Function CanResetValue(component As Object) As Boolean
        Return False
    End Function

    Public Overrides ReadOnly Property ComponentType As Type
        Get
            Return GetType(TColl)
        End Get
    End Property

    Public Overrides Function GetValue(component As Object) As Object
        Dim coll = DirectCast(component, Collection(Of TItem))
        Return coll(_index)
    End Function

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

    Public Overrides ReadOnly Property PropertyType As Type
        Get
            Return GetType(TItem)
        End Get
    End Property

    Public Overrides Sub ResetValue(component As Object)

    End Sub

    Public Overrides Sub SetValue(component As Object, value As Object)

    End Sub

    Public Overrides Function ShouldSerializeValue(component As Object) As Boolean
        Return False
    End Function

End Class

Вы можете связать все с вашими классами, используя:

Me.AssignTypeConverter(Of MyCustomClass, ExpandableObjectConverter)()
Me.AssignTypeConverter(Of MyCustomClassCollection, MyCollectionTypeDescriptor(Of MyCustomClassCollection, MyCustomClass))()

Это должно перечислить каждый элемент в основной сетке свойств, и каждый элемент будет расширяемым встроенным. Это то, что вы ищете?

  • 0
    Хм, наверное, я должен был прочитать связанную статью , которая довольно похожа и спасла бы немного работы! :-)
  • 0
    Похоже, что моя коллекция сериализуется в виде списка при прохождении через веб-сервис, поэтому я изменил As Collection(Of TItem) -> IList . В остальном работал отлично, спасибо за идеальный ответ! +1 и принимаю.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню