2007年9月13日木曜日

プロパティでSystem.Typeを指定したい?(3)

前回書いた6つのメソッドの中で、まずはGetStandardValuesメソッドとGetStandardValuesSupportedメソッドから。

「標準値リスト」を提供する部分に関わるメソッドで、IDE側ではGetStandardValuesSupportedメソッドがTrueを返した際に、GetStandardValuesメソッドでドロップダウンリストに表示する一覧を取得しにくる、という流れになっているのよ。

んじゃ今回提供したい標準値リストって何が入っていればいいか?と言われると。

「自分のプロジェクトと参照設定されているアセンブリなどに存在するクラスの一覧」

が目標になるわけだ。同じようなものとしては、DataGridViewのカラムを設定するあたりだね。あれと同じ動き。とりあえず説明はあとで大体のロジックを。

''' <summary>設定対象となるクラスの一覧を取得します</summary>
Protected Function GetClassList(ByVal context As System.ComponentModel.ITypeDescriptorContext) As ArrayList
    Dim service As ComponentModel.Design.IDesignerHost _
        = DirectCast(context.GetService(GetType(ComponentModel.Design.IDesignerHost)), ComponentModel.Design.IDesignerHost)
    Dim discoveryService As ComponentModel.Design.ITypeDiscoveryService _
        = DirectCast(service.GetService(GetType(ComponentModel.Design.ITypeDiscoveryService)), ComponentModel.Design.ITypeDiscoveryService)

    Dim result As New ArrayList
    For Each childtype As System.Type In Me.FilterGenericTypes(discoveryService.GetTypes(Me._targetType, False))
        If ((childtype Is Me._targetType) OrElse childtype.IsAbstract) OrElse _
            (Not childtype.IsPublic AndAlso Not childtype.IsNestedPublic) Then Continue For

        Dim attribute As DataGridViewColumnDesignTimeVisibleAttribute _
            = TryCast(ComponentModel.TypeDescriptor.GetAttributes(childtype).Item(GetType(DataGridViewColumnDesignTimeVisibleAttribute)), DataGridViewColumnDesignTimeVisibleAttribute)

        If (attribute Is Nothing) OrElse attribute.Visible Then result.Add(childtype)
    Next
    Return result
End Function

''' <summary>インスタンス化できないクラスを一覧から除去します</summary>
Private Function FilterGenericTypes(ByVal childTypes As ICollection) As ICollection
    If (childTypes Is Nothing) OrElse _
       (childTypes.Count = 0) Then Return childTypes

    Dim childArray As New ArrayList(childTypes.Count)
    For Each type As System.Type In childTypes
        If Not type.ContainsGenericParameters Then childArray.Add(type)
    Next
    Return childArray
End Function

中々お目にかからないクラスが多いと思う。IDesignerHostとかITypeDiscoveryServiceとか。ざっくりと言ってしまうと、ITypeDiscoveryServiceインターフェースは「プロジェクトと参照設定されているアセンブリ」に対して探し物をしてくれるクラスが継承しているもの。IDesignerHostインターフェースはMSDNあたりで見てくださいw
なのでITypeDiscoveryServiceを利用してクラス一覧を取得、んでその中からインスタンス化できないクラスを除去。もう一つついでにデザイン時に利用していいクラスかどうか(DataGridViewColumnDesignTimeVisibleAttribute)を判断して一覧を整理してあげればOK。ただ、最後の属性を見てってのは特にやらなくても問題ないケースが多いかな。デザイン時には非表示だけど実行時には使いたいようなクラスを自前で用意するような、そんな面白いケースになった時にこの属性を使ってあげていればいいんだけどね。今のところであってません、そんなケースにはw

これで標準値リストについては大体OK。このロジックは、コントロールを拡張しだすと結構使いたい場面が多くなる・・・人もいるかな?

0 件のコメント:

コメントを投稿