none
コントロールのプロパティの作成方法 RRS feed

  • 質問

  • お世話になっております。

    VB2008.NETを使って、Windowsフォームアプリケーションを作成しております。

    コントロール Button、Textboxを継承して、プロパティを追加したいのですが

    プロパティに配列は指定できませんか?

    原因はよくわかっておりませんが、デザイナーが壊れます。

    また、プロパティを、階層分けしたいのですが、方法がわかりません。

    SizeとかのプロパティはW,Dが階層分けされていますが、

    同様に自作のプロパティを階層分けして表示したいです。

    以上、ご教示よろしくお願いします。

    2016年9月14日 12:42

回答

  •  VS2010で配列型のプロパティを試してみましたがデザイナーが壊れることの再現ができないです。
    どんな型の配列であるかを提示してもらえると再現テストができるかもしれません。

    プロパティを展開可能にするには、その型にTypeConverterAttributeでExpandableObjectConverterを指定すると楽です。
    #指定できない場合は小細工する必要があるのでちょっと面倒

    Imports System.ComponentModel
    
    Public Class ButtonEx
        Inherits Button
    
        Public Property Test0 As Integer()
            Get
                Return _Test
            End Get
            Set(value As Integer())
                _Test = value
            End Set
        End Property
        Private _Test As Integer()
    
        Public Property Test1 As Item1()
            Get
                Return _Test2
            End Get
            Set(value As Item1())
                _Test2 = value
            End Set
        End Property
        Private _Test2 As Item1()
    End Class
    
    '自作のクラスを展開可能にしたい場合は
    'TypeConverterAttributeにExpandableObjectConverterをクラスに指定してやる
    <System.ComponentModel.TypeConverter(GetType(System.ComponentModel.ExpandableObjectConverter))> _
    Public Class Item1
        Sub New(ByVal a As Integer)
    
        End Sub
        Public Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
        Private _X As Integer
    
        Public Property Y As Integer
            Get
                Return _Y
            End Get
            Set(value As Integer)
                _Y = value
            End Set
        End Property
        Private _Y As Integer
    End Class
    
    '*******************************************
    
    'ExpandableObjectConverterの指定されてない型のプロパティを強制的に展開可能にする場合
    <TypeConverter(GetType(ExpandableSubObjectConverter))> _
    Public Class TextBoxEx
        Inherits TextBox
    
        'ExpandableObjectConverterが指定されていない型のプロパティ
        Public Property Test2 As Item2
            Get
                Return _Test2
            End Get
            Set(value As Item2)
                _Test2 = value
            End Set
        End Property
        Private _Test2 As Item2
    End Class
    
    Public Structure Item2
        Public Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
        Private _X As Integer
    
        Public Property Y As Integer
            Get
                Return _Y
            End Get
            Set(value As Integer)
                _Y = value
            End Set
        End Property
        Private _Y As Integer
    End Structure
    
    
    '強制的に展開可能にするためのコンバーター
    Friend Class ExpandableSubObjectConverter
        Inherits ExpandableObjectConverter
    
        Public Overrides Function GetProperties(ByVal context As ITypeDescriptorContext, ByVal value As Object, ByVal attributes As Attribute()) As PropertyDescriptorCollection
            Dim ps = MyBase.GetProperties(context, value, attributes)
            Dim list As List(Of PropertyDescriptor) = New List(Of PropertyDescriptor)()
            For Each pd As PropertyDescriptor In ps
                Dim tca As TypeConverterAttribute = Nothing
                For Each attr As Attribute In pd.Attributes
                    tca = TryCast(attr, TypeConverterAttribute)
                    If tca IsNot Nothing Then
                        Exit For
                    End If
                Next
    
                If tca Is Nothing Then
                    list.Add(New ExpandPropertyDescriptor(pd))
                Else
                    list.Add(pd)
                End If
            Next
    
            Dim retval As PropertyDescriptorCollection = New PropertyDescriptorCollection(list.ToArray())
            Return retval
        End Function
    
        Public Overrides Function GetPropertiesSupported(ByVal context As ITypeDescriptorContext) As Boolean
            Dim b = MyBase.GetPropertiesSupported(context)
            Return True
        End Function
    
        Private Class ExpandPropertyDescriptor
            Inherits PropertyDescriptor
    
            Public Sub New(ByVal pd As PropertyDescriptor, Optional ByVal isExpandSubProperties As Boolean = True)
                MyBase.New(pd)
                baseDescriptor = pd
                If isExpandSubProperties Then
                    Dim list As List(Of Attribute) = New List(Of Attribute)(MyBase.AttributeArray)
                    Dim tca As TypeConverterAttribute = New TypeConverterAttribute(GetType(ExpandableSubObjectConverter))
                    list.Add(tca)
                    MyBase.AttributeArray = list.ToArray()
                End If
            End Sub
    
            Private Shared expandable As ExpandableObjectConverter = New ExpandableObjectConverter()
    
            Private baseDescriptor As PropertyDescriptor
    
            Public Overrides ReadOnly Property Converter As TypeConverter
                Get
                    Dim conv = MyBase.Converter
                    If TypeOf conv Is TypeConverter Then
                        Return expandable
                    Else
                        Return conv
                    End If
                End Get
            End Property
    
            Public Overrides Function CanResetValue(ByVal component As Object) As Boolean
                Return baseDescriptor.CanResetValue(component)
            End Function
    
            Public Overrides ReadOnly Property ComponentType As Type
                Get
                    Return baseDescriptor.ComponentType
                End Get
            End Property
    
            Public Overrides Function GetValue(ByVal component As Object) As Object
                Return baseDescriptor.GetValue(component)
            End Function
    
            Public Overrides ReadOnly Property IsReadOnly As Boolean
                Get
                    Return baseDescriptor.IsReadOnly
                End Get
            End Property
    
            Public Overrides ReadOnly Property PropertyType As Type
                Get
                    Return baseDescriptor.PropertyType
                End Get
            End Property
    
            Public Overrides Sub ResetValue(ByVal component As Object)
                baseDescriptor.ResetValue(component)
            End Sub
    
            Public Overrides Sub SetValue(ByVal component As Object, ByVal value As Object)
                baseDescriptor.SetValue(component, value)
            End Sub
    
            Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
                Return baseDescriptor.ShouldSerializeValue(component)
            End Function
        End Class
    End Class



    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク to1109 2016年10月21日 2:38
    2016年9月14日 14:23

すべての返信

  • to1109 さま よろしく。

    SizeとかのプロパティはW,Dが階層分け > Size と言う構造体が予め用意されています。

    以下が参考になりますでしょうか?。

     https://msdn.microsoft.com/ja-jp/library/system.drawing.size(v=vs.90).aspx
     https://msdn.microsoft.com/ja-jp/library/4ft0z102(v=vs.100).aspx

    2016年9月14日 14:10
  •  VS2010で配列型のプロパティを試してみましたがデザイナーが壊れることの再現ができないです。
    どんな型の配列であるかを提示してもらえると再現テストができるかもしれません。

    プロパティを展開可能にするには、その型にTypeConverterAttributeでExpandableObjectConverterを指定すると楽です。
    #指定できない場合は小細工する必要があるのでちょっと面倒

    Imports System.ComponentModel
    
    Public Class ButtonEx
        Inherits Button
    
        Public Property Test0 As Integer()
            Get
                Return _Test
            End Get
            Set(value As Integer())
                _Test = value
            End Set
        End Property
        Private _Test As Integer()
    
        Public Property Test1 As Item1()
            Get
                Return _Test2
            End Get
            Set(value As Item1())
                _Test2 = value
            End Set
        End Property
        Private _Test2 As Item1()
    End Class
    
    '自作のクラスを展開可能にしたい場合は
    'TypeConverterAttributeにExpandableObjectConverterをクラスに指定してやる
    <System.ComponentModel.TypeConverter(GetType(System.ComponentModel.ExpandableObjectConverter))> _
    Public Class Item1
        Sub New(ByVal a As Integer)
    
        End Sub
        Public Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
        Private _X As Integer
    
        Public Property Y As Integer
            Get
                Return _Y
            End Get
            Set(value As Integer)
                _Y = value
            End Set
        End Property
        Private _Y As Integer
    End Class
    
    '*******************************************
    
    'ExpandableObjectConverterの指定されてない型のプロパティを強制的に展開可能にする場合
    <TypeConverter(GetType(ExpandableSubObjectConverter))> _
    Public Class TextBoxEx
        Inherits TextBox
    
        'ExpandableObjectConverterが指定されていない型のプロパティ
        Public Property Test2 As Item2
            Get
                Return _Test2
            End Get
            Set(value As Item2)
                _Test2 = value
            End Set
        End Property
        Private _Test2 As Item2
    End Class
    
    Public Structure Item2
        Public Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
        Private _X As Integer
    
        Public Property Y As Integer
            Get
                Return _Y
            End Get
            Set(value As Integer)
                _Y = value
            End Set
        End Property
        Private _Y As Integer
    End Structure
    
    
    '強制的に展開可能にするためのコンバーター
    Friend Class ExpandableSubObjectConverter
        Inherits ExpandableObjectConverter
    
        Public Overrides Function GetProperties(ByVal context As ITypeDescriptorContext, ByVal value As Object, ByVal attributes As Attribute()) As PropertyDescriptorCollection
            Dim ps = MyBase.GetProperties(context, value, attributes)
            Dim list As List(Of PropertyDescriptor) = New List(Of PropertyDescriptor)()
            For Each pd As PropertyDescriptor In ps
                Dim tca As TypeConverterAttribute = Nothing
                For Each attr As Attribute In pd.Attributes
                    tca = TryCast(attr, TypeConverterAttribute)
                    If tca IsNot Nothing Then
                        Exit For
                    End If
                Next
    
                If tca Is Nothing Then
                    list.Add(New ExpandPropertyDescriptor(pd))
                Else
                    list.Add(pd)
                End If
            Next
    
            Dim retval As PropertyDescriptorCollection = New PropertyDescriptorCollection(list.ToArray())
            Return retval
        End Function
    
        Public Overrides Function GetPropertiesSupported(ByVal context As ITypeDescriptorContext) As Boolean
            Dim b = MyBase.GetPropertiesSupported(context)
            Return True
        End Function
    
        Private Class ExpandPropertyDescriptor
            Inherits PropertyDescriptor
    
            Public Sub New(ByVal pd As PropertyDescriptor, Optional ByVal isExpandSubProperties As Boolean = True)
                MyBase.New(pd)
                baseDescriptor = pd
                If isExpandSubProperties Then
                    Dim list As List(Of Attribute) = New List(Of Attribute)(MyBase.AttributeArray)
                    Dim tca As TypeConverterAttribute = New TypeConverterAttribute(GetType(ExpandableSubObjectConverter))
                    list.Add(tca)
                    MyBase.AttributeArray = list.ToArray()
                End If
            End Sub
    
            Private Shared expandable As ExpandableObjectConverter = New ExpandableObjectConverter()
    
            Private baseDescriptor As PropertyDescriptor
    
            Public Overrides ReadOnly Property Converter As TypeConverter
                Get
                    Dim conv = MyBase.Converter
                    If TypeOf conv Is TypeConverter Then
                        Return expandable
                    Else
                        Return conv
                    End If
                End Get
            End Property
    
            Public Overrides Function CanResetValue(ByVal component As Object) As Boolean
                Return baseDescriptor.CanResetValue(component)
            End Function
    
            Public Overrides ReadOnly Property ComponentType As Type
                Get
                    Return baseDescriptor.ComponentType
                End Get
            End Property
    
            Public Overrides Function GetValue(ByVal component As Object) As Object
                Return baseDescriptor.GetValue(component)
            End Function
    
            Public Overrides ReadOnly Property IsReadOnly As Boolean
                Get
                    Return baseDescriptor.IsReadOnly
                End Get
            End Property
    
            Public Overrides ReadOnly Property PropertyType As Type
                Get
                    Return baseDescriptor.PropertyType
                End Get
            End Property
    
            Public Overrides Sub ResetValue(ByVal component As Object)
                baseDescriptor.ResetValue(component)
            End Sub
    
            Public Overrides Sub SetValue(ByVal component As Object, ByVal value As Object)
                baseDescriptor.SetValue(component, value)
            End Sub
    
            Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
                Return baseDescriptor.ShouldSerializeValue(component)
            End Function
        End Class
    End Class



    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク to1109 2016年10月21日 2:38
    2016年9月14日 14:23
  • だいぶ、返信遅くなり申し訳ありません。

    gekka様の方法の

    '自作のクラスを展開可能にしたい場合は
    'TypeConverterAttributeにExpandableObjectConverterをクラスに指定してやる

    は、

    TEST1の項目だけ表示されて展開はでてきません。

    VS2008だからでしょうか・・・。

    'ExpandableObjectConverterの指定されてない型のプロパティを強制的に展開可能にする場合
    <TypeConverter(GetType(ExpandableSubObjectConverter))> _

    こちらは、できました。

    ですが、こちらは、ほとんどのプロパティに+がついてしまいますね。

    ま、問題はないのです。

    ありがとうございました。

    2016年10月21日 2:38