none
PropertyGrid の SelectedObjects について RRS feed

  • 質問

  • VS2008/.NET2.0ベースで開発を行なっております。

    PropertyGrid の SelectedObjects にオブジェクト配列を与えると、複数のオブジェクトのメンバを一括で変更できる機能を理解しました。

    オブジェクトが以下のようになっている場合、

    Private Class Cobj
    
      Private _ID As Integer
      Private _group As String
    
      <System.ComponentModel.DisplayName("ID")> _
      Public Property ID() As Integer
        Get
          Return Me._ID
        End Get
        Set(ByVal value As Integer)
          Me._ID = value
        End Set
      End Property
    
      <System.ComponentModel.DisplayName("グループ名")> _
      Public Property group() As String
        Get
          Return Me._group
        End Get
        Set(ByVal value As String)
          Me._group = value
        End Set
      End Property
    
    End Class
    この時、
    1. ID は一括変更の対象にしたくない。つまり、SelectedObjects で他のオブジェクトと一緒に選択された場合は変更を無効にしたいが、SelectedObject で単独で選択された場合は、変更の対象にしたい。
    2. group は単独選択だろうが、一括選択であろうが、自由に変更できる。

    としたいです。

    どのように記述すれば良いのでしょうか。

    2012年3月27日 1:35

回答

  • PropertyGridは、開発者が使うように設計されていて、エンドユーザというかコンシューマに見せる用途はあまり考えられてないような気がしますが……(個人的感想です)。

    以下は、型記述子についてある程度の知識がないと難しいと思います。必要ならMSDNで「型記述子の概要」以下を読んだりしてください。出てくる型の名前とかでWEB検索するのもいいでしょう。

    PropertyGridは、System.ComponentModelの設計に従って型記述子(TypeDescriptor)を元にオブジェクトのメタ情報を収集します。

    メタ情報の核となるのはTypeConverterクラスです。TypeConverterクラスにはGetPropertiesメソッドが用意されており、そのTypeConverterが扱うオブジェクトのプロパティの集合を返します。PropertyGridはこれを使用します。

    TypeConverterは必要に応じて継承し独自の型コンバータを実装することができます。GetPropertiesもオーバーライド可能であり、型またはインスタンスのプロパティを追加削除、あるいはまったく別の物に差し替えたりプロクシとして別インスタンスのプロパティを返したりもできます。

    オーバーライド可能なGetPropertiesメソッドは引数にITypeDescriptorContextがあり、このInstanceプロパティが型変換を要求している実際のオブジェクトを指していて、PropertyGridが要求したとき、SelectedObjectであればオブジェクトそのものが、SelectedObjectsであればオブジェクトの配列が格納されているため、これで判断ができます。

    // なお、GetPropertiesをオーバーライドするときは同時にGetPropertiesSupportedのオーバーライドも必要です。

    さて、カスタム型コンバータの実装ができたとして、あとはどうやってこの型コンバータを目的のクラスまたはオブジェクトに適用するかです。

    適用対象のクラスを変更できるなら、TypeConverterAttribute属性を適用するのがもっとも簡単でしょう。これなら対象のクラスに属性を宣言するだけです。

    元のクラスを変更できないのであれば、話はやや面倒になります。既存の型またはインスタンスにあとから(実行時に)型情報を追加するには、TypeDescriptorのAddProviderメソッドを使用するのですが、これにはTypeConverterではなくTypeDescriptionProviderを渡す必要があり、これも派生が必要です。

    ここでTypeDescriptionProviderの主眼となるのはGetTypeDescriptorですが、これもまだTypeConverterではなくICustomTypeDescriptorを返すメソッドです。

    ICustomTypeDescriptorは基本実装となるCustomTypeDescriptorが用意されており、これを継承して、GetConverterメソッドをオーバーライドすることでようやく型コンバータを変更するように指示できます。

    // もっと楽な手はないものかしら-。

    • 回答としてマーク ぐさん 2012年3月27日 4:14
    2012年3月27日 3:12

すべての返信

  • PropertyGridは、開発者が使うように設計されていて、エンドユーザというかコンシューマに見せる用途はあまり考えられてないような気がしますが……(個人的感想です)。

    以下は、型記述子についてある程度の知識がないと難しいと思います。必要ならMSDNで「型記述子の概要」以下を読んだりしてください。出てくる型の名前とかでWEB検索するのもいいでしょう。

    PropertyGridは、System.ComponentModelの設計に従って型記述子(TypeDescriptor)を元にオブジェクトのメタ情報を収集します。

    メタ情報の核となるのはTypeConverterクラスです。TypeConverterクラスにはGetPropertiesメソッドが用意されており、そのTypeConverterが扱うオブジェクトのプロパティの集合を返します。PropertyGridはこれを使用します。

    TypeConverterは必要に応じて継承し独自の型コンバータを実装することができます。GetPropertiesもオーバーライド可能であり、型またはインスタンスのプロパティを追加削除、あるいはまったく別の物に差し替えたりプロクシとして別インスタンスのプロパティを返したりもできます。

    オーバーライド可能なGetPropertiesメソッドは引数にITypeDescriptorContextがあり、このInstanceプロパティが型変換を要求している実際のオブジェクトを指していて、PropertyGridが要求したとき、SelectedObjectであればオブジェクトそのものが、SelectedObjectsであればオブジェクトの配列が格納されているため、これで判断ができます。

    // なお、GetPropertiesをオーバーライドするときは同時にGetPropertiesSupportedのオーバーライドも必要です。

    さて、カスタム型コンバータの実装ができたとして、あとはどうやってこの型コンバータを目的のクラスまたはオブジェクトに適用するかです。

    適用対象のクラスを変更できるなら、TypeConverterAttribute属性を適用するのがもっとも簡単でしょう。これなら対象のクラスに属性を宣言するだけです。

    元のクラスを変更できないのであれば、話はやや面倒になります。既存の型またはインスタンスにあとから(実行時に)型情報を追加するには、TypeDescriptorのAddProviderメソッドを使用するのですが、これにはTypeConverterではなくTypeDescriptionProviderを渡す必要があり、これも派生が必要です。

    ここでTypeDescriptionProviderの主眼となるのはGetTypeDescriptorですが、これもまだTypeConverterではなくICustomTypeDescriptorを返すメソッドです。

    ICustomTypeDescriptorは基本実装となるCustomTypeDescriptorが用意されており、これを継承して、GetConverterメソッドをオーバーライドすることでようやく型コンバータを変更するように指示できます。

    // もっと楽な手はないものかしら-。

    • 回答としてマーク ぐさん 2012年3月27日 4:14
    2012年3月27日 3:12
  • 丁寧かつご親切なご返信、ありがとうございます。

    > PropertyGridは、開発者が使うように設計されていて、エンドユーザというかコンシューマに見せる用途はあまり考えられてないような気がしますが……(個人的感想です)。

    確かにそういう印象は受けました。クラスの中身を動的に GUI 画面として表現できるものは、他のウィジェット環境でもあまり見掛けないのでなかなか画期的だと感じてはおりますが、「そのまま用いるのは、ある程度の用途まで」と割り切って使う方がいいのかな、とも思っています。

    > TypeConverterは必要に応じて継承し独自の型コンバータを実装することができます。

    はい。こちらも経験したことがあります。独自の型(例えば、3次元座標 X Y Z 型など)を PropertyGrid 上で展開させる為に、TypeConverter を用いた事があります。

    > PropertyGridが要求したとき、SelectedObjectであればオブジェクトそのものが、SelectedObjectsであればオブジェクトの配列が格納されているため、これで判断ができます。

    なるほど、ITypeDescriptorContext ですね!

    > 適用対象のクラスを変更できるなら、TypeConverterAttribute属性を適用するのがもっとも簡単でしょう。これなら対象のクラスに属性を宣言するだけです。

    この方法で試してみたいと考えております。
    非常に参考になりました。
    2012年3月27日 4:14