展开属性网格中的集合而不对类进行任何修改?

时间:2014-06-12 15:10:32

标签: c# vb.net propertygrid typedescriptor

此方法适用于除集合之外的所有内容:

收藏品显示如下:

enter image description here

所以尽管它们是可扩展的,但它们在属性网格中的用处并不多。

以下是我要查找的内容示例(截图取自here):

enter image description here

链接文章还包含一些代码,可以实现这一点,但需要修改原始类。在它与我之前的问题之间,我提出了一些想法,但我不太熟悉使用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,但如果你说C#,请随意使用。

1 个答案:

答案 0 :(得分:2)

在评论中继续太久了,但是这样的事情怎么样 - 将每个集合项转换为属性(ItemX)的自定义ExpandableObjectConverter,以及获取相应项的自定义属性描述符。

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))()

应该列出主属性网格中的每个项目,每个项目都可以内联展开。那是你在找什么?