VB のたまご

作成日: 2018/11/06, 更新日: 2018/11/06


型コンバータ

  • この投稿は Visual Basic Advent Calendar 2018 の 7 日目の記事です。
    ・ 6 日目の記事: デザイナ
    ・ 8 日目の記事:

  •  プロパティウィンドウに表示された各プロパティは、全て文字列で表示されていて更新も文字列でおこないますが、全てが文字列型のプロパティなわけではありません。 例えば、Form の Size プロパティ内の Width, Height プロパティは、Integer 型ですが、文字列で設定しても問題なく処理されています。

  •  この役目を担当しているのが型コンバータです。WPF の IValueConverter に似ています。以下サンプルです。
  • Imports System.ComponentModel
    Imports System.Globalization
    
    ' テスト対象の独自クラス
    <TypeConverter(GetType(PersonConverter))>
    Public Class Person
    
        Public Property Name As String
        Public Property Age As Integer
    
        Public Sub New(name As String, age As Integer)
            Me.Name = name
            Me.Age = age
        End Sub
    
        Public Overrides Function ToString() As String
            Return $"{Name}, {Age}"
        End Function
    
    End Class
    
    '  通常は、TypeConverter を継承します。
    '  ExpandableObjectConverter を継承しているのは、サンプル動作の確認のためプロパティウィンドウに表示して、
    '  プロパティのメンバーを展開したかったため ExpandableObjectConverter を継承しています。
    Public Class PersonConverter
        Inherits ExpandableObjectConverter
    
        ' 文字列型から Person 型に変換できるかどうか
        Public Overrides Function CanConvertFrom(context As ITypeDescriptorContext, sourceType As Type) As Boolean
    
            If sourceType Is GetType(String) Then
                Return True
            End If
    
            Return MyBase.CanConvertFrom(context, sourceType)
    
        End Function
    
        ' 文字列から Person 型に変換
        Public Overrides Function ConvertFrom(context As ITypeDescriptorContext, culture As CultureInfo, value As Object) As Object
    
            If TypeOf value Is String Then
    
                Dim s = value.ToString()
                If Not s.Contains(",") Then
                    MessageBox.Show("カンマで区切って、名前と年齢を入力ください。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
                    Return New Person(String.Empty, 0)
                End If
    
                Dim items = s.Split(New Char() {","c})
                Return New Person(items(0), Integer.Parse(items(1)))
    
            End If
    
            Return MyBase.ConvertFrom(context, culture, value)
    
        End Function
    
    
    
        ' Person 型から文字列型に変換できるかどうか
        Public Overrides Function CanConvertTo(context As ITypeDescriptorContext, destinationType As Type) As Boolean
    
            If destinationType Is GetType(Person) Then
                Return True
            End If
    
            Return MyBase.CanConvertTo(context, destinationType)
    
        End Function
    
        ' Person 型から文字列型に変換
        Public Overrides Function ConvertTo(context As ITypeDescriptorContext, culture As CultureInfo, value As Object, destinationType As Type) As Object
    
            If destinationType Is GetType(String) Then
                Dim p = CType(value, Person)
                Return $"{p.Name}, {p.Age}"
            End If
    
            Return MyBase.ConvertTo(context, culture, value, destinationType)
    
        End Function
    
    
    
        ' ConvertToString() に対応する逆変換ヘルパー
        Public Function ConvertToObject(value As String) As Person
    
            If CanConvertFrom(value.GetType()) Then
    
                Dim obj = ConvertFrom(value)
                If TypeOf obj Is Person Then
                    Return CType(obj, Person)
                End If
    
            End If
    
            Return New Person(String.Empty, 0)
    
        End Function
    
    End Class
    

  •  型コンバータは System.ComponentModel.TypeConverter を継承して作成します。が、 ここではプロパティウィンドウで詳細を展開できる System.ComponentModel.ExpandableObjectConverter を継承しました。 これを、型コンバートを提供したいクラスに属性として付与して使います。

  •  処理内容はシンプルで、文字列から任意の型へ、任意の型から文字列型に変換する処理を書くだけです。実際の変換処理と事前の変換可能チェック処理を作ってあげます。 WPF の ICommand にも(ry ですね。

  • イメージ
  •  こんな感じです。