こんにちは!開発現場の第一線で、日々コードと格闘している先輩エンジニアです。
今回は、Windows Formsアプリ開発の隠れた名脇役、`PropertyGrid`(プロパティグリッド)コントロールを徹底的に使いこなす方法についてお話しします。
「カスタムクラスを作ったけれど、PropertyGridに表示させると『(コレクション)』と表示されるだけで中身が編集できない…」
「プロパティの色や数値を、もっと直感的にドロップダウンや専用ダイアログでいじれるようにしたい!」
そんな壁にぶつかったことはありませんか?
この悩みを鮮やかに解決するのが、今回解説する`TypeConverter`(タイプコンバーター)の実装です。
ここをクリアすれば、VB.NETでのオブジェクト指向の理解が一段と深まり、GUIアプリケーションのクオリティが劇的に跳ね上がりますよ。さあ、一緒にプロの技をマスターしていきましょう!
—
1. なぜPropertyGridはそのままでは動かないのか?
Windows Formsの`PropertyGrid`は、オブジェクトのプロパティをリフレクション(型の自己検査)によって自動で解析し、一覧表示してくれる非常に強力なコントロールです。
しかし、あなたが定義した「独自の複雑なクラス(カスタムデータ型)」を別のクラスのプロパティとして持たせた場合、PropertyGridはそれをどう文字列化し、どうやってユーザーからの入力を受け付ければいいのか判断できません。
そこで登場するのが、`TypeConverter`クラスです。
こいつをカスタムクラスに紐付けることで、PropertyGridに対して「このオブジェクトは、こういう風に文字列に変換して表示し、こういう風に編集させるんだよ」と手取り足取り教えてあげることができます。
—
2. 今回作成するサンプルと全体像
今回は、社員の「氏名(String)」と「役職(Enum)」をひとまとめにした、`EmployeeInfo`というカスタムクラスを作ります。これを、メイン画面の`PropertyGrid`上で自由自在に編集できるようにしてみましょう。
全体の仕組みはこうです:
1. カスタムクラス (`EmployeeInfo`): 編集したいデータ構造。
2. TypeConverter (`EmployeeInfoConverter`): 文字列とオブジェクトの相互変換を担当する翻訳者。
3. メインフォーム (`MainForm`): `PropertyGrid`を配置する舞台。
—
3. 実装コード(VB.NET)
さっそく、実際のコードを見ていきましょう。プロジェクトにそのままコピペして試せるように、コメントをたっぷりと書き込んでいます。
Imports System.ComponentModel
Imports System.Globalization
‘ ==========================================
‘ 1. 役職を表す列挙体 (Enum)
‘ ==========================================
Public Enum PositionType
Staff = 0
Manager = 1
Director = 2
Executive = 3
End Enum
‘ ==========================================
‘ 2. カスタムデータ型 (ここにTypeConverterを指定!)
‘ ==========================================
Public Class EmployeeInfo
‘ プロパティ:氏名
Public Property Name As String = “未設定”
‘ プロパティ:役職
Public Property Position As PositionType = PositionType.Staff
‘ ★超重要:PropertyGridがオブジェクトを正しく表示・認識するために
‘ ToString()をオーバーライドして「概要文字列」を返します。
Public Overrides Function ToString() As String
Return $”{Name} ({Position})”
End Function
End Class
‘ ==========================================
‘ 3. TypeConverterの実装(ここが今回のキモ!)
‘ ==========================================
Public Class EmployeeInfoConverter
Inherits ExpandableObjectConverter ‘ ★入れ子構造を展開できるようにする賢い基底クラス
‘ ① オブジェクトから文字列(PropertyGridの右側に表示される文字)への変換
Public Overrides Function ConvertTo(context As ITypeDescriptorContext, culture As CultureInfo, value As Object, destinationType As Type) As Object
If destinationType = GetType(String) AndAlso TypeOf value Is EmployeeInfo Then
Dim emp As EmployeeInfo = CType(value, EmployeeInfo)
‘ ToString()の結果をそのままグリッドの表示文字にする
Return emp.ToString()
End If
Return MyBase.ConvertTo(context, culture, value, destinationType)
End Function
‘ ② 文字列からオブジェクトへの変換(必要に応じてテキスト入力をパースする場合に使う)
Public Overrides Function ConvertFrom(context As ITypeDescriptorContext, culture As CultureInfo, value As Object) As Object
If TypeOf value Is String Then
‘ 今回は簡易的に、カンマ区切りなどで入力された場合の処理を想定(省略も可)
Dim parts = CStr(value).Split(CChar(“,”))
Dim emp As New EmployeeInfo()
If parts.Length > 0 Then emp.Name = parts(0).Trim()
Return emp
End If
Return MyBase.ConvertFrom(context, culture, value)
End Function
‘ ③ ユーザーがテキストボックスから直接入力できるかどうか(今回はFalse=グリッドの階層展開や専用UIに任せる)
Public Overrides Function CanConvertFrom(context As ITypeDescriptorContext, sourceType As Type) As Boolean
If sourceType = GetType(String) Then
Return True
End If
Return MyBase.CanConvertFrom(context, sourceType)
End Function
Public Overrides Function CanConvertTo(context As ITypeDescriptorContext, destinationType As Type) As Boolean
If destinationType = GetType(String) Then
Return True
End If
Return MyBase.CanConvertTo(context, destinationType)
End Function
End Class
‘ ==========================================
‘ 4. アプリケーション設定用のメインクラス(PropertyGridにバインドする対象)
‘ ==========================================
Public Class AppSettings
Public Property SectionName As String = “開発部”
‘ ここに先ほどのカスタムクラスを配置!
Public Property MainEmployee As EmployeeInfo = New EmployeeInfo()
End Class
—
4. フォームへの組み込みと動作確認
あとは、Windows Formsの画面(Form1など)に `PropertyGrid` コントロールを1つ配置し、コードビハインドでインスタンスを渡すだけです。
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
‘ 設定オブジェクトのインスタンスを作成
Dim settings As New AppSettings()
‘ PropertyGridにオブジェクトをセット!
Me.PropertyGrid1.SelectedObject = settings
End Sub
End Class
これを実行して `PropertyGrid` を見てみてください。
「担当社員情報」の行の左側に `[+]` マークが現れ、クリックすると「氏名」や「役職」の項目が美しく展開されます。さらに、役職の項目をクリックすると、親切なドロップダウンメニューから `Staff` や `Manager` を選択できるようになっています!
—
5. 陥りやすい罠とエンジニアの知見(Tips)
ここで、現場でハマりがちなポイントをいくつかシェアしておきます。
1. `ExpandableObjectConverter` を継承すること
`TypeConverter` をそのまま継承すると、コードをたくさん書く必要があります。入れ子(ツリー状)のプロパティを展開したい場合は、必ず `ExpandableObjectConverter` を継承してください。これだけで面倒なツリー展開の処理を自動で肩代わりしてくれます。
2. `ToString()` の実装を忘れない
コンバーター内で `ConvertTo` をオーバーライドしていても、元となるカスタムクラス側で `ToString()` が適切にoverrideされていないと、PropertyGrid上には冷たく `(Collection)` やクラス名のフルパスが表示されてしまいます。
3. イミュータブル(不変)なクラスに注意
PropertyGridは、ユーザーが値を書き換えた際に対応するプロパティの `Set` アクセサを呼び出します。カスタムクラスが読み取り専用(ReadOnly)になっていると値が保存されないため、必ず `Public Property`(Setあり)として設計しましょう。
—
まとめ
いかがでしょうか?
一見難しそうに見える `TypeConverter` ですが、役割を分解して理解すれば、独自のデータ型をPropertyGridの王国にスムーズに迎え入れるための強力なパスポートになります。
ここをクリアできれば、設定画面やパラメータエディタを持つ本格的なデスクトップアプリケーションをVB.NETでサクッと作れるようになりますよ。
Visual Basic / VB.NETの表現力と、.NETの強力なフレームワークの組み合わせは、まだまだ第一線で戦える素晴らしい武器です。ぜひあなたの開発プロジェクトでも試してみてくださいね。それでは、次のテック記事でお会いしましょう!
