.NET コンボボックスのオーナードロー ~カラーコンボボックス~

カラーコンボボックスのサンプルです。

コンボボックスのオーナードローはあちこちで解説されているので、そちらを参考にしてください。
DOBON.NETさん ComboBoxの項目を自分で描画する

今回参考にさせていただいたのはこちら。C#です。
Out Of Memoryさん オーナードローでデータバインドなコンボボックスのサンプル
DataSourceに設定したデータからDisplayMemberの値を取りだすところで、悩んでました。
たいへん参考になりました。ありがとうございます。


カラーコンボボックスのサンプルです。
Imports System.ComponentModel

Public Class ColorComboBox
    Inherits System.Windows.Forms.ComboBox


    Private _ColorMember As String

    Public Property ColorMember() As String
        Get
            Return Me._ColorMember
        End Get
        Set(ByVal value As String)
            Me._ColorMember = value
        End Set
    End Property


    Public Sub New()
        InitializeComponent()

        'アイテムの高さが均一の描画
        Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawFixed

    End Sub


    Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)

        '描画領域の取得
        Dim rctColor As New RectangleF(e.Bounds.Left, e.Bounds.Top, CSng(e.Bounds.Width * 0.3), e.Bounds.Height)
        Dim rctText As New RectangleF(rctColor.Right + CSng(e.Bounds.Width * 0.1), e.Bounds.Top, e.Bounds.Width, e.Bounds.Height)
        Dim rctTextBack As New RectangleF(rctColor.Right, e.Bounds.Top, e.Bounds.Width, e.Bounds.Height)


        '文字列の描画
        If (e.Index <> -1) Then
            '--表示する文字列の取得 
            Dim objTxt As Object = Me.Items(e.Index)
            If (Me.DataSource IsNot Nothing) Then
                Dim properties As PropertyDescriptorCollection = Me.BindingContext(Me.DataSource).GetItemProperties()
                Dim prpDisplayMember As PropertyDescriptor = properties(Me.DisplayMember)
                If (prpDisplayMember IsNot Nothing) Then
                    objTxt = prpDisplayMember.GetValue(Me.Items(e.Index))
                End If
            End If
            Dim txt As String = System.ComponentModel.TypeDescriptor.GetConverter(objTxt).ConvertToString(objTxt)

            '--表示する文字列の書式
            Dim sf As StringFormat = CType(StringFormat.GenericDefault.Clone, StringFormat)
            sf.Alignment = StringAlignment.Near
            sf.LineAlignment = StringAlignment.Center
            '--文字列領域の前景色と背景色の取得
            Dim clrTxtBack As Color
            Dim clrTxtFore As Color
            If ((e.State And DrawItemState.Disabled) <> 0) Then
                clrTxtBack = SystemColors.Window
                clrTxtFore = SystemColors.GrayText
            ElseIf (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
                If (e.State And DrawItemState.ComboBoxEdit) = DrawItemState.ComboBoxEdit Then
                    clrTxtBack = SystemColors.Window
                    clrTxtFore = Me.ForeColor
                Else
                    clrTxtBack = SystemColors.Highlight
                    clrTxtFore = SystemColors.HighlightText
                End If
            Else
                clrTxtBack = SystemColors.Window
                clrTxtFore = Me.ForeColor
            End If
            '--文字列領域の描画
            Using brush As New SolidBrush(clrTxtBack)
                e.Graphics.FillRectangle(brush, rctTextBack)
            End Using
            Using brush As New SolidBrush(clrTxtFore)
                e.Graphics.DrawString(txt, e.Font, brush, rctText, sf)
            End Using

            'カラーボックスの描画
            '--表示するカラーの取得
            Dim objClr As Object = Me.Items(e.Index)
            If (Me.DataSource IsNot Nothing) Then
                Dim properties As PropertyDescriptorCollection = Me.BindingContext(Me.DataSource).GetItemProperties()
                Dim prpColorMember As PropertyDescriptor = properties(Me.ColorMember)
                If (prpColorMember IsNot Nothing) Then
                    objClr = prpColorMember.GetValue(Me.Items(e.Index))
                End If
            End If
            Dim clr As Color = CType(objClr, System.Drawing.Color)
            Using backBrush As New SolidBrush(clr)
                e.Graphics.FillRectangle(backBrush, rctColor)
            End Using

        End If

        ''Forcus枠の描画
        'If ((e.State And DrawItemState.Focus) <> 0) Then
        '    e.DrawFocusRectangle()
        'End If

    End Sub


End Class

テストコードです。
フォームにカラーコンボボックスを2つ配置し以下のコードを実行します。
Public Class Form1


    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim props As System.Reflection.PropertyInfo() = GetType(Color).GetProperties(System.Reflection.BindingFlags.Public Or System.Reflection.BindingFlags.Static)

        'ItemsプロパティにColorオブジェクトを追加
        Dim items As New List(Of Object)
        For Each prop As System.Reflection.PropertyInfo In props
            If (prop.PropertyType IsNot GetType(Color)) Then
                Continue For
            End If
            Dim color As Color = CType(prop.GetValue(Nothing, Nothing), Color)
            If (color = color.Transparent) Then
                Continue For
            Else
                items.Add(color)
            End If
        Next
        Me.ColorComboBox1.Items.AddRange(items.ToArray)

        'DataSourceにDataTableを指定
        Dim dt As New DataTable()
        dt.Columns.Add("Cd", GetType(Integer))
        dt.Columns.Add("Color", GetType(Color))
        dt.Columns.Add("Name", GetType(String))
        Dim cd As Integer = 1
        For Each prop As System.Reflection.PropertyInfo In props
            If (prop.PropertyType IsNot GetType(Color)) Then
                Continue For
            End If
            Dim color As Color = CType(prop.GetValue(Nothing, Nothing), Color)
            If (color = color.Transparent) Then
                Continue For
            Else
                dt.Rows.Add(cd, color, color.Name)
                cd += 1
            End If
        Next

        Me.ColorComboBox2.ValueMember = "Cd"
        Me.ColorComboBox2.DisplayMember = "Name"
        Me.ColorComboBox2.ColorMember = "Color"
        Me.ColorComboBox2.DataSource = dt


    End Sub
End Class

.NET 定数ファイルを作成する ~その8~ 定数のシリアライズ・デシリアライズをカスタマイズする

.NET 定数ファイルを作成する ~その1~
.NET 定数ファイルを作成する ~その2~
.NET 定数ファイルを作成する ~その3~
.NET 定数ファイルを作成する ~その4~ インテリセンスに候補を表示する
.NET 定数ファイルを作成する ~その5~ 定数のリストを作成する
.NET 定数ファイルを作成する ~その6~ 定数を「=」演算子で比較できるようにする
.NET 定数ファイルを作成する ~その7~ 定数をシリアライズ・デシリアライズできるようにする

.NET シリアライズ・デシリアライズ ~XmlSerializerクラス~

前回は定数アイテムをシリアライズ出来るようにしました。
出力されたXMLファイルをみるとWeekDayクラスのCd,Name,AliasNameがすべて出力されています。

前回出力したXMLファイル
<?xml version="1.0"?>
<SerializeSample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Cd>1</Cd>
  <WeekDay>
    <Cd>6</Cd>
    <Name>金曜日</Name>
    <AliasName>金</AliasName>
  </WeekDay>
</SerializeSample>

このファイルからデシリアライズするとSerializeSampleオブジェクトのWeekDayTypeオブジェクトはCd=6,Name=金曜日,AliasName=金となります。

WeekDayTypeクラスのAliasNameを「FriDay」に変更したとします。
Public Shared ReadOnly Fri As New WeekDayType(6, "金曜日", "FriDay")

その後、前回出力したXMLファイルからSerializeSampleオブジェクトをデシリアライズすると、
SerializeSampleオブジェクトのWeekDayTypeオブジェクトはCd=6,Name=金曜日,AliasName=金のままです。

シリアライズはWeekDayTypeオブジェクトのCDだけを出力し、
デシリアライズはそのCDを元に、WeekDayTypeクラスのPublic Shared ReadOnlyフィールドからオブジェクトを復元したいと思います。

出力したいXMLファイル
<?xml version="1.0"?>
<SerializeSample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Cd>1</Cd>
  <WeekDay>6</WeekDay>
</SerializeSample>

ConstantItemのNameプロパティとAliasNameプロパティにXmlIgnore属性をつければ、
シリアライズ対象外になりXMLファイルには出力されないようになります。
このようにして出力したXMLファイルからSerializeSampleオブジェクトをデシリアライズすると、
SerializeSampleオブジェクトのWeekDayTypeオブジェクトはCd=6,Name="",AliasName=""となります。
XmlIgnore属性では対応できない細かな制御はIXmlSerializableインターフェイスを実装し、
WriteXmlメソッド、ReadXmlメソッドに記述します。

またデシリアライズで復元したオブジェクトはWeekDayTypeクラスのPublic Shared ReadOnlyで定義されている定数オブジェクトとは異なるため、
Equalsメソッドで比較するとFalseを返すようになります。
そこでEqualsメソッドではCdが同じならTrueを返すようオーバーライドします。
EqualsメソッドをオーバーライドしたのでGetHashCodeメソッドもオーバーライドします。
GetHashCodeメソッドはEqualsメソッドがTrueならば、そのオブジェクトは同じHashCodeを返すようにしなければいけません。
今回はCdの比較だけなので、GetHashCodeメソッドはCdを返せばよいです。
2つ以上の値をEqualsメソッドで比較した場合などはそれぞれの値をXorします。


Imports System.Xml
Imports System.Xml.Serialization

Namespace Constant
    ''' <summary>
    ''' 定数アイテムの基底クラスです。
    ''' </summary>
     _
    Public MustInherit Class ConstantItem
        Implements IXmlSerializable

        '-----フィールド-----

        ''' <summary>コード</summary>
        Protected _iCd As Integer
        ''' <summary>名前</summary>
        Protected _sName As String
        ''' <summary>別名</summary>
        Protected _sAliasName As String

        '-----Publicプロパティ-----

        ''' <summary>コードを取得します</summary>
        Public Property Cd() As Integer
            Get
                Return Me._iCd
            End Get
            Set(ByVal value As Integer)
                Me._iCd = value
            End Set
        End Property
        ''' <summary>名前を取得します。</summary>
        Public Property Name() As String
            Get
                Return Me._sName
            End Get
            Set(ByVal value As String)
                Me._sName = value
            End Set
        End Property
        ''' <summary>別名を取得します。</summary>
        Public Property AliasName() As String
            Get
                Return Me._sAliasName
            End Get
            Set(ByVal value As String)
                Me._sAliasName = value
            End Set
        End Property

        '-----コンストラクタ-----

        ''' <summary>引数を取らないコンストラクタ</summary>
        Protected Sub New()
            'シリアライズの為に必要です。
        End Sub
        ''' <summary>コードと名前を引数に取るコンストラクタ</summary>
        Public Sub New(ByVal cd As Integer, ByVal name As String)
            MyBase.New()
            Me._iCd = cd
            Me._sName = name
        End Sub
        ''' <summary>コードと名前と別名を引数に取るコンストラクタ</summary>
        Public Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            Me.New(cd, name)
            Me._sAliasName = aliasname
        End Sub

        '-----Public Overridesメソッド-----

        ''' <summary>
        ''' ToStringメソッド
        ''' </summary>
        Public Overrides Function ToString() As String
            Return String.Format("Cd={0},Nmae={1},AliasName={2}", Me._iCd, Me._sName, Me._sAliasName)
        End Function
        
        ''' <summary>
        ''' Equalsメソッド
        ''' </summary>
        Public Overrides Function Equals(ByVal obj As Object) As Boolean
            If (obj Is Nothing) OrElse (Not Me.GetType() Is obj.GetType()) Then
                Return False
            Else
                Return (Me.Cd = DirectCast(obj, ConstantItem).Cd)
            End If
        End Function

        ''' <summary>
        ''' GetHashCodeメソッド
        ''' </summary>
        Public Overrides Function GetHashCode() As Integer
            Return Me.Cd
        End Function
        
        '-----Operator-----

        ''' <summary>
        ''' =オペレータ
        ''' </summary>
        Public Shared Operator =(ByVal left As ConstantItem, ByVal right As ConstantItem) As Boolean
            'cdが同じなら=の結果もtrueとする。
            If (left Is Nothing) OrElse (right Is Nothing) Then
                Return (left Is Nothing) And (right Is Nothing)
            Else
                Return (left.Cd = right.Cd)
            End If
        End Operator

        ''' <summary>
        ''' <>オペレータ
        ''' </summary>
        Public Shared Operator <>(ByVal left As ConstantItem, ByVal right As ConstantItem) As Boolean
            If (left Is Nothing) OrElse (right Is Nothing) Then
                Return Not ((left Is Nothing) And (right Is Nothing))
            Else
                Return Not (left.Cd = right.Cd)
            End If
        End Operator

        '-----Protectedメソッド-----

        ''' <summary>
        ''' 定数定義リストを取得します。デシリアライズの為に必要です。
        ''' </summary>
        Protected MustOverride Function GetItems() As IList

        '-----IXmlSerializableインタフェースのimplementsメソッド-----

        ''' <summary>
        ''' IXmlSerializableインターフェイスを実装する場合、このメソッドから Nothingを返す必要があります。
        ''' </summary>
        Public Function GetSchema() As System.Xml.Schema.XmlSchema _
        Implements System.Xml.Serialization.IXmlSerializable.GetSchema
            Return Nothing
        End Function

        ''' <summary>
        ''' オブジェクトの XML 表現からオブジェクトを生成します。
        ''' </summary>
        Public Sub ReadXml(ByVal reader As System.Xml.XmlReader) _
        Implements System.Xml.Serialization.IXmlSerializable.ReadXml
            'デシリアライズするときは、CdからName,AliasNameを検索します。
            '定数定義リストを返すメソッド  Protected MustOverride Function GetItems() As IListを
            '派生クラスでオーバーライドする必要があります。
          
            reader.Read()
            
            If reader.HasValue Then
                Dim icd As Integer = Integer.Parse(reader.ReadString)
                For Each o As Object In GetItems()
                    Dim item As ConstantItem = DirectCast(o, ConstantItem)
                    If item.Cd = icd Then
                        Me._iCd = item.Cd
                        Me._sName = item.Name
                        Me._sAliasName = item.AliasName
                        Exit For
                    End If
                Next
            End If

            reader.ReadEndElement()
        End Sub

        ''' <summary>
        ''' オブジェクトを XML 表現に変換します。
        ''' </summary>
        Public Sub WriteXml(ByVal writer As System.Xml.XmlWriter) _
        Implements System.Xml.Serialization.IXmlSerializable.WriteXml
            'シリアライズするときは、Cdのみをシリアライズします。
            writer.WriteValue(Me._iCd)
        End Sub

    End Class
End Namespace


WeekDayTypeクラスではGetItemsメソッドをオーバーライドします。
Namespace Constant

    ''' <summary>
    ''' 曜日
    ''' </summary>
    ''' 
    Public NotInheritable Class WeekDayType : Inherits ConstantItem

        Public Shared Shadows ReadOnly Items As New ConstantItemCollection(Of WeekDayType)

        Public Shared ReadOnly Sun As New WeekDayType(1, "日曜日", "日")
        Public Shared ReadOnly Mon As New WeekDayType(2, "月曜日", "月")
        Public Shared ReadOnly Tue As New WeekDayType(3, "火曜日", "火")
        Public Shared ReadOnly Wed As New WeekDayType(4, "水曜日", "水")
        Public Shared ReadOnly Thr As New WeekDayType(5, "木曜日", "木")
        Public Shared ReadOnly Fri As New WeekDayType(6, "金曜日", "金")
        Public Shared ReadOnly Sat As New WeekDayType(7, "土曜日", "土")

        Private Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            MyBase.new(cd, name, aliasname)
            Items.Add(Me)

        End Sub
        '---以下シリアライズの為に必要です。-----
        Private Sub New()
        End Sub

        Protected Overrides Function GetItems() As System.Collections.IList
            Return Items
        End Function

    End Class

   
End Namespace

ConstantItemCollectionクラス 前回より変更はありません。
Namespace Constant
    ''' <summary>
    ''' 定数アイテムを管理するコレクションクラスです。
    ''' </summary>
    Public Class ConstantItemCollection(Of T As ConstantItem)
        Inherits List(Of T)
        Implements ICloneable


        ''' <summary>
        ''' 定義されている定数アイテムより、引数に指定したcdをもつアイテムを検索します。
        ''' </summary>
        Public Function GetItem(ByVal cd As Integer) As T
            For idx As Integer = 0 To Me.Count - 1
                If cd = CType(Me.Item(idx), ConstantItem).Cd Then
                    Return CType(Me.Item(idx), T)
                End If
            Next
            Return Nothing
        End Function

        ''' <summary>
        ''' 定義されている定数アイテムより、引数に指定したnameをもつアイテムを検索します。
        ''' </summary>
        Public Function GetItem(ByVal name As String) As T
            For idx As Integer = 0 To Me.Count - 1
                If name = CType(Me.Item(idx), ConstantItem).Name Then
                    Return CType(Me.Item(idx), T)
                End If
            Next
            Return Nothing
        End Function

        ''' <summary>
        ''' Copyメソッド
        ''' </summary>
        ''' 
        ''' 
        Public Function Copy() As ConstantItemCollection(Of T)
            Return DirectCast(Me.Clone(), ConstantItemCollection(Of T))
        End Function

        '-----ICloneableインターフェースのimplementsメソッド-----

        ''' <summary>
        ''' Cloneメソッド
        ''' </summary>
        Private Function Clone() As Object Implements System.ICloneable.Clone
            '戻り値がObject型だと不便なのでPrivateにしCopyメソッドをPublicで公開します。
            Return Me.MemberwiseClone()
        End Function
    End Class
End Namespace

これでシリアライズではWeekDayTypeオブジェクトのCDだけを出力し、
デシリアライズはそのCDを元に、WeekDayTypeクラスのPublic Shared ReadOnlyフィールドからオブジェクトを復元できました。

テストのためにWeekDayTypeクラスをフィールドメンバにもつクラスを作成します。
<Serializable()> _
Public Class SerializeSample

    Private _cd As Integer
    Private _weekDay As Constant.WeekDayType

    Public Property Cd() As Integer
        Get
            Return Me._cd
        End Get
        Set(ByVal value As Integer)
            Me._cd = value
        End Set
    End Property

    Public Property WeekDay() As Constant.WeekDayType
        Get
            Return Me._weekDay
        End Get
        Set(ByVal value As Constant.WeekDayType)
            Me._weekDay = value
        End Set
    End Property

    Public Sub New()
    End Sub

End Class
WeekDayTypeクラスをフィールドメンバにもつSerializeSampleクラスをシリアライズ・デシリアライズします。
Public Class Form1
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'シリアライズ
        Dim ss As New SerializeSample
        ss.Cd = 1
        ss.WeekDay = Constant.WeekDayType.Fri

        Using fs As New System.IO.FileStream("D:\test.xml", IO.FileMode.Create, IO.FileAccess.Write)
            Dim xs As New System.Xml.Serialization.XmlSerializer(GetType(SerializeSample))
            xs.Serialize(fs, ss)
            fs.Close()
        End Using
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        'デシリアライズ
        Dim ss As SerializeSample

        Using fs As New System.IO.FileStream("D:\test.xml", IO.FileMode.Open)
            Dim xs As New System.Xml.Serialization.XmlSerializer(GetType(SerializeSample))
            ss = CType(xs.Deserialize(fs), SerializeSample)
            fs.Close()
        End Using

        Console.WriteLine(ss.Cd)
        Console.WriteLine(ss.WeekDay.ToString)
    End Sub
End Class

.NET 定数ファイルを作成する ~その7~ 定数をシリアライズ・デシリアライズできるようにする

.NET 定数ファイルを作成する ~その1~
.NET 定数ファイルを作成する ~その2~
.NET 定数ファイルを作成する ~その3~
.NET 定数ファイルを作成する ~その4~ インテリセンスに候補を表示する
.NET 定数ファイルを作成する ~その5~ 定数のリストを作成する
.NET 定数ファイルを作成する ~その6~ 定数を「=」演算子で比較できるようにする

.NET シリアライズ・デシリアライズ ~XmlSerializerクラス~


前回作成した定数クラスをシリアライズ・デシリアライスできるように変更したいと思います。
XmlSerializerクラスを使用してシリアライズ・デシリアライズする場合の注意点は
・引数を取らないコンストラクタが定義されていること。
・シリアライズ対象のプロパティはSetter、Getterがともに定義されていること。

前回作成した定数クラス(ConstantItemクラス)のプロパティはReadOnlyプロパティだったのでSetterを定義します。
引数を取らないコンストラクタも定義します。
クラスにSerializable属性をつけます。
Namespace Constant

    ''' <summary>
    ''' 定数アイテムの基底クラスです。
    ''' </summary>
    <Serializable()> _
    Public MustInherit Class ConstantItem

        '-----フィールド-----

        ''' <summary>コード</summary>
        Protected _iCd As Integer
        ''' <summary>名前</summary>
        Protected _sName As String
        ''' <summary>別名</summary>
        Protected _sAliasName As String

        '-----Publicプロパティ-----

        ''' <summary>コードを取得します</summary>
         Public Property Cd() As Integer
            Get
                Return Me._iCd
            End Get
            Set(ByVal value As Integer)
                Me._iCd = value
            End Set
        End Property
        ''' <summary>名前を取得します。</summary>
        Public Property Name() As String
            Get
                Return Me._sName
            End Get
            Set(ByVal value As String)
                Me._sName = value
            End Set
        End Property
        ''' <summary>別名を取得します。</summary>
        Public Property AliasName() As String
            Get
                Return Me._sAliasName
            End Get
            Set(ByVal value As String)
                Me._sAliasName = value
            End Set
        End Property

        '-----コンストラクタ-----

        ''' <summary>引数を取らないコンストラクタ</summary>
        Protected Sub New()
            'シリアライズの為に必要です。
        End Sub
        
        ''' <summary>コードと名前を引数に取るコンストラクタ</summary>
        Public Sub New(ByVal cd As Integer, ByVal name As String)
            MyBase.New()
            Me._iCd = cd
            Me._sName = name
        End Sub
        
        ''' <summary>コードと名前と別名を引数に取るコンストラクタ</summary>
        Public Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            Me.New(cd, name)
            Me._sAliasName = aliasname
        End Sub
        
        '-----Public Overridesメソッド-----

        ''' <summary>
        ''' ToStringメソッド
        ''' </summary>
        Public Overrides Function ToString() As String
            Return String.Format("Cd={0},Nmae={1},AliasName={2}", Me._iCd, Me._sName, Me._sAliasName)
        End Function

        '-----Operator-----

        ''' <summary<
        ''' =オペレータ
        ''' </summary<
        Public Shared Operator =(ByVal left As ConstantItem, ByVal right As ConstantItem) As Boolean
            'cdが同じなら=の結果もtrueとする。
            If (left Is Nothing) OrElse (right Is Nothing) Then
                Return (left Is Nothing) And (right Is Nothing)
            Else
                Return (left.Cd = right.Cd)
            End If
        End Operator

        ''' <summary>
        ''' <>オペレータ
        ''' </summary>
        Public Shared Operator <>(ByVal left As ConstantItem, ByVal right As ConstantItem) As Boolean
            If (left Is Nothing) OrElse (right Is Nothing) Then
                Return Not ((left Is Nothing) And (right Is Nothing))
            Else
                Return Not (left.Cd = right.Cd)
            End If
        End Operator
        
    End Class
End Namespace

WeekDayTypeクラスにもデフォルトコンストラクタを追加します。
Namespace Constant

    ''' <summary>
    ''' 曜日
    ''' </summary>
    ''' <completionlist cref="WeekDayType"/>
    Public NotInheritable Class WeekDayType : Inherits ConstantItem
        Public Shared Shadows ReadOnly Items As New ConstantItemCollection(Of WeekDayType)

        Public Shared ReadOnly Sun As New WeekDayType(1, "日曜日", "日")
        Public Shared ReadOnly Mon As New WeekDayType(2, "月曜日", "月")
        Public Shared ReadOnly Tue As New WeekDayType(3, "火曜日", "火")
        Public Shared ReadOnly Wed As New WeekDayType(4, "水曜日", "水")
        Public Shared ReadOnly Thr As New WeekDayType(5, "木曜日", "木")
        Public Shared ReadOnly Fri As New WeekDayType(6, "金曜日", "金")
        Public Shared ReadOnly Sat As New WeekDayType(7, "土曜日", "土")

        Private Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            MyBase.new(cd, name, aliasname)
            Items.Add(Me)
        End Sub
        Private Sub New()
           'シリアライズの為に必要です。
        End Sub
    End Class

End Namespace

ConstantItemCollectionクラス 前回のまま変更はありません。
Namespace Constant
    ''' <summary>
    ''' 定数アイテムを管理するコレクションクラスです。
    ''' </summary>
    Public Class ConstantItemCollection(Of T As ConstantItem)
        Inherits List(Of T)
        Implements ICloneable
        
        ''' <summary>
        ''' 定義されている定数アイテムより、引数に指定したcdをもつアイテムを検索します。
        ''' </summary>
        Public Function GetItem(ByVal cd As Integer) As T
            For idx As Integer = 0 To Me.Count - 1
                If cd = CType(Me.Item(idx), ConstantItem).Cd Then
                    Return CType(Me.Item(idx), T)
                End If
            Next
            Return Nothing
        End Function

        ''' <summary>
        ''' 定義されている定数アイテムより、引数に指定したnameをもつアイテムを検索します。
        ''' </summary>
        Public Function GetItem(ByVal name As String) As T
            For idx As Integer = 0 To Me.Count - 1
                If name = CType(Me.Item(idx), ConstantItem).Name Then
                    Return CType(Me.Item(idx), T)
                End If
            Next
            Return Nothing
        End Function
        
        ''' <summary>
        ''' Copyメソッド
        ''' </summary>
        Public Function Copy() As ConstantItemCollection(Of T)
            Return DirectCast(Me.Clone(), ConstantItemCollection(Of T))
        End Function

        '-----ICloneableインターフェースのimplementsメソッド-----

        ''' <summary>
        ''' Cloneメソッド
        ''' </summary>
        Private Function Clone() As Object Implements System.ICloneable.Clone
            '戻り値がObject型だと不便なのでPrivateにしCopyメソッドをPublicで公開します。
            Return Me.MemberwiseClone()
        End Function
        
    End Class
End Namespace

テストのためにWeekDayTypeクラスをフィールドメンバにもつクラスを作成します。
<Serializable()> _
Public Class SerializeSample

    Private _cd As Integer
    Private _weekDay As Constant.WeekDayType

    Public Property Cd() As Integer
        Get
            Return Me._cd
        End Get
        Set(ByVal value As Integer)
            Me._cd = value
        End Set
    End Property

    Public Property WeekDay() As Constant.WeekDayType
        Get
            Return Me._weekDay
        End Get
        Set(ByVal value As Constant.WeekDayType)
            Me._weekDay = value
        End Set
    End Property

    Public Sub New()
    End Sub

End Class
WeekDayTypeクラスをフィールドメンバにもつSerializeSampleクラスをシリアライズ・デシリアライズします。
Public Class Form1
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'シリアライズ
        Dim ss As New SerializeSample
        ss.Cd = 1
        ss.WeekDay = Constant.WeekDayType.Fri

        Using fs As New System.IO.FileStream("D:\test.xml", IO.FileMode.Create, IO.FileAccess.Write)
            Dim xs As New System.Xml.Serialization.XmlSerializer(GetType(SerializeSample))
            xs.Serialize(fs, ss)
            fs.Close()
        End Using
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        'デシリアライズ
        Dim ss As SerializeSample

        Using fs As New System.IO.FileStream("D:\test.xml", IO.FileMode.Open)
            Dim xs As New System.Xml.Serialization.XmlSerializer(GetType(SerializeSample))
            ss = CType(xs.Deserialize(fs), SerializeSample)
            fs.Close()
        End Using

        Console.WriteLine(ss.Cd)
        Console.WriteLine(ss.WeekDay.ToString)
    End Sub
End Class

出力されたXMLファイル
<?xml version="1.0"?>
<SerializeSample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Cd>1</Cd>
  <WeekDay>
    <Cd>6</Cd>
    <Name>金曜日</Name>
    <AliasName>金</AliasName>
  </WeekDay>
</SerializeSample>

.NET シリアライズ・デシリアライズ ~XmlSerializerクラス~

オブジェクトの内容をファイルに保存(シリアライズ)、また復元(デシリアライズ)しようと思います。
方法は3種類あります。
  1. System.Xml.Serialization.XmlSerializerクラスを使用する方法
  2. System.Runtime.Serialization.Formatters.Soap.SoapFormatterクラスを使用する方法
  3. System.Runtime.Serialization.Formatters.Binary.BinaryFormatter クラスを使用する方法


XmlSerializerクラスはオブジェクトをXMLファイルに保存復元できます。
私が良く使うのは設定ファイルなどをExcelで記述し、ExcelからXMLに出力します。
そのXMLファイルを読み込んでオブジェクトに復元しアプリ内で使用したりしています。


SoapFormatterクラスはオブジェクトをSOAP仕様に従ってXMLファイルに保存復元できます。
Webサービスとデータをやり取りする場合に使用しています。


BinaryFormatterクラスはオブジェクトをバイナリファイルに保存復元できます。
ユーザーに簡単に変更されたくない場合などに使用しています。


参考URL
DOBON.NETN オブジェクトの内容をバイナリファイルに保存する
DOBON.NETN オブジェクトの内容をファイルに保存、復元する
@IT 連載 .NETで簡単XML
伊勢的新常識 XmlSerializer について


XmlSerializerクラスを使用してオブジェクトをXMLファイルに保存・復元する


System.Xml.Serialization.XmlSerializerクラスを使用しオブジェクトをXMLファイルに保存・復元します。
基本的にクラスにSerializable属性をつけるだけでシリアライズ・デシリアライズ可能です。
シリアライズしたくないプロパティにはXmlIgnore属性をつけます。

注意点
シリアライズ・デシリアライスするプロパティはSetter、Getterの両方が必要。
引数を取らないコンストラクタが必要。(特に引数を取るコンストラクタを定義した場合はデフォルトコンストラクタがないので明示的に引数を取らないコンストラクタを定義する)

簡単なサンプルです。
Public Class Form1
 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
     'シリアライズ
     Dim ss As New SerializeSample
     ss.Cd = 1
     ss.Child = New Child("taro", 5)

     Using fs As New System.IO.FileStream("D:\SerializeSample.xml", IO.FileMode.Create, IO.FileAccess.Write)
         Dim xs As New System.Xml.Serialization.XmlSerializer(GetType(SerializeSample))
         xs.Serialize(fs, ss)
         fs.Close()
     End Using
 End Sub

 Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
   'デシリアライズ
     Dim ss As SerializeSample

     Using fs As New System.IO.FileStream("D:\SerializeSamplet.xml", IO.FileMode.Open)
         Dim xs As New System.Xml.Serialization.XmlSerializer(GetType(SerializeSample))
         ss = CType(xs.Deserialize(fs), SerializeSample)
         fs.Close()
     End Using

     Console.WriteLine(ss.Cd)
     Console.WriteLine(ss.Child.ToString)
 End Sub
End Class

<Serializable()> _
Public Class SerializeSample

    Private _cd As Integer
    Private _child As Child
    Private _unSerialize As String

    Public Property Cd() As Integer
        Get
            Return Me._cd
        End Get
        Set(ByVal value As Integer)
            Me._cd = value
        End Set
    End Property

    Public Property Child() As Child
        Get
            Return Me._child
        End Get
        Set(ByVal value As Child)
            Me._child = value
        End Set
    End Property

    <System.Xml.Serialization.XmlIgnore()> _
    Public Property UnSerialize() As String
        Get
            Return Me._unSerialize
        End Get
        Set(ByVal value As String)
            Me._unSerialize = value
        End Set
    End Property

    Public Sub New()
    End Sub

End Class

<Serializable()> _
Public Class Child

    Private _name As String
    Private _age As Integer

    Public Property Name() As String
        Get
            Return Me._name
        End Get
        Set(ByVal value As String)
            Me._name = value
        End Set
    End Property

    Public Property Age() As Integer
        Get
            Return Me._age
        End Get
        Set(ByVal value As Integer)
            Me._age = value
        End Set
    End Property


    Protected Sub New()
    End Sub

    Public Sub New(ByVal name As String, ByVal age As Integer)
        Me._name = name
        Me._age = age
    End Sub

    Public Overrides Function ToString() As String
        Return String.Format("Name:{0} Age:{1}", Me._name, Me._age)
    End Function

End Class

出力されたXMLファイルです。
<?xml version="1.0"?>
<SerializeSample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Cd>1</Cd>
  <Child>
    <Name>taro</Name>
    <Age>5</Age>
  </Child>
</SerializeSample>

.NET 定数ファイルを作成する ~その6~ 定数を「=」演算子で比較できるようにする

.NET 定数ファイルを作成する ~その1~
.NET 定数ファイルを作成する ~その2~
.NET 定数ファイルを作成する ~その3~
.NET 定数ファイルを作成する ~その4~ インテリセンスに候補を表示する
.NET 定数ファイルを作成する ~その5~ 定数のリストを作成する

System.Drawing.Colorオブジェクトは「=」や「<>」で比較することができます。
Dim c1 As System.Drawing.Color = Color.Red
Dim c2 As System.Drawing.Color = Color.Red
Console.WriteLine("c1=c2:" & (c1 = c2))
Console.WriteLine("c1<>c2:" & (c1 <> c2))

しかし前回作成したConstantItemクラスは「=」や「<>」で比較するとコンパイルエラーになってしまいます。
そこで、System.Drawing.Colorと同じように「=」や「<>」で比較できるように、
前回(.NET 定数ファイルを作成する ~その5~ 定数のリストを作成する)作成したConstantItemに変更を加えます。

「=」演算子と「<>」演算子をオーバーロードし、_iCdフィールドの値が同じなら「=」演算子はtrueを返すようにします。
Namespace Constant

    ''' <summary>
    ''' 定数アイテムの基底クラスです。
    ''' </summary>
    Public MustInherit Class ConstantItem

        '-----フィールド-----

        ''' <summary>コード</summary>
        Protected _iCd As Integer
        ''' <summary>名前</summary>
        Protected _sName As String
        ''' <summary>別名</summary>
        Protected _sAliasName As String

        '-----Publicプロパティ-----

        ''' <summary>コードを取得します</summary>
        Public ReadOnly Property Cd() As Integer
            Get
                Return Me._iCd
            End Get
        End Property
        ''' <summary>名前を取得します。</summary>
        Public ReadOnly Property Name() As String
            Get
                Return Me._sName
            End Get
        End Property
        ''' <summary>別名を取得します。</summary>
        Public ReadOnly Property AliasName() As String
            Get
                Return Me._sAliasName
            End Get
        End Property

        '-----コンストラクタ-----

        ''' <summary>引数を取らないコンストラクタ</summary>
        Private Sub New()
        End Sub
        ''' <summary>コードと名前を引数に取るコンストラクタ</summary>
        Public Sub New(ByVal cd As Integer, ByVal name As String)
            MyBase.New()
            Me._iCd = cd
            Me._sName = name
        End Sub
        ''' <summary>コードと名前と別名を引数に取るコンストラクタ</summary>
        Public Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            Me.New(cd, name)
            Me._sAliasName = aliasname
        End Sub
        
        '-----Public Overridesメソッド-----

        ''' <summary>
        ''' ToStringメソッド
        ''' </summary>
        Public Overrides Function ToString() As String
            Return String.Format("Cd={0},Nmae={1},AliasName={2}", Me._iCd, Me._sName, Me._sAliasName)
        End Function

        '-----Operator-----

        ''' <summary<
        ''' =オペレータ
        ''' </summary<
        Public Shared Operator =(ByVal left As ConstantItem, ByVal right As ConstantItem) As Boolean
            'cdが同じなら=の結果もtrueとする。
            If (left Is Nothing) OrElse (right Is Nothing) Then
                Return (left Is Nothing) And (right Is Nothing)
            Else
                Return (left.Cd = right.Cd)
            End If
        End Operator

        ''' <summary>
        ''' <>オペレータ
        ''' </summary>
        Public Shared Operator <>(ByVal left As ConstantItem, ByVal right As ConstantItem) As Boolean
            If (left Is Nothing) OrElse (right Is Nothing) Then
                Return Not ((left Is Nothing) And (right Is Nothing))
            Else
                Return Not (left.Cd = right.Cd)
            End If
        End Operator
        
    End Class
End Namespace

WeekDayTypeクラス 前回のまま変更はありません。
Namespace Constant

    ''' <summary>
    ''' 曜日
    ''' </summary>
    Public NotInheritable Class WeekDayType : Inherits ConstantItem
        
        Public Shared ReadOnly Items As New ConstantItemCollection(Of WeekDayType)

        Public Shared ReadOnly Sun As New WeekDayType(1, "日曜日", "日")
        Public Shared ReadOnly Mon As New WeekDayType(2, "月曜日", "月")
        Public Shared ReadOnly Tue As New WeekDayType(3, "火曜日", "火")
        Public Shared ReadOnly Wed As New WeekDayType(4, "水曜日", "水")
        Public Shared ReadOnly Thr As New WeekDayType(5, "木曜日", "木")
        Public Shared ReadOnly Fri As New WeekDayType(6, "金曜日", "金")
        Public Shared ReadOnly Sat As New WeekDayType(7, "土曜日", "土")

        Private Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            MyBase.new(cd, name, aliasname)
            Items.Add(Me)
        End Sub

    End Class
End Namespace

ConstantItemCollectionクラス 前回のまま変更はありません。
Namespace Constant
Namespace Constant
    ''' <summary>
    ''' 定数アイテムを管理するコレクションクラスです。
    ''' </summary>
    Public Class ConstantItemCollection(Of T As ConstantItem)
        Inherits List(Of T)
        Implements ICloneable
        
        ''' <summary>
        ''' 定義されている定数アイテムより、引数に指定したcdをもつアイテムを検索します。
        ''' </summary>
        Public Function GetItem(ByVal cd As Integer) As T
            For idx As Integer = 0 To Me.Count - 1
                If cd = CType(Me.Item(idx), ConstantItem).Cd Then
                    Return CType(Me.Item(idx), T)
                End If
            Next
            Return Nothing
        End Function

        ''' <summary>
        ''' 定義されている定数アイテムより、引数に指定したnameをもつアイテムを検索します。
        ''' </summary>
        Public Function GetItem(ByVal name As String) As T
            For idx As Integer = 0 To Me.Count - 1
                If name = CType(Me.Item(idx), ConstantItem).Name Then
                    Return CType(Me.Item(idx), T)
                End If
            Next
            Return Nothing
        End Function
        
        ''' <summary>
        ''' Copyメソッド
        ''' </summary>
        Public Function Copy() As ConstantItemCollection(Of T)
            Return DirectCast(Me.Clone(), ConstantItemCollection(Of T))
        End Function

        '-----ICloneableインターフェースのimplementsメソッド-----

        ''' <summary>
        ''' Cloneメソッド
        ''' </summary>
        Private Function Clone() As Object Implements System.ICloneable.Clone
            '戻り値がObject型だと不便なのでPrivateにしCopyメソッドをPublicで公開します。
            Return Me.MemberwiseClone()
        End Function
        
    End Class
End Namespace

これで「=」や「<>」での比較もコンパイルエラーになりません。
Dim w1 As Constant.DayOfWeekType = Constant.DayOfWeekType.Fri
Dim w2 As Constant.DayOfWeekType = Constant.DayOfWeekType.Fri
Console.WriteLine("w1=w2:" & (w1 = w2))
Console.WriteLine("w1<>w2:" & (w1 <> w2))

.NET 定数ファイルを作成する ~その5~ 定数のリストを作成する

.NET 定数ファイルを作成する ~その1~
.NET 定数ファイルを作成する ~その2~
.NET 定数ファイルを作成する ~その3~
.NET 定数ファイルを作成する ~その4~ インテリセンスに候補を表示する


以前も書きましたが、WeekDayTypeクラスに定義されている定数メンバをコンボボックスのDataSourceに設定したい場面があります。
その都度リストを作るのが面倒なので、WeekDayTypeクラスに定数リストを持たせたいと思います。

またWeekDayTypeのCd=1のWeekDayTypeオブジェクトを取得できるようにしたいと思います。
こちらはデータベースなどにWeekDayTypeのCd「1」が保存されており、それに対応したWeekDayTypeオブジェクトを取得したいなどといった場面で使用します。


WeekDayTypeクラスにはItemsメンバを追加し、コンストラクタでItemsに定数を追加していきます。
Namespace Constant

    ''' <summary>
    ''' 曜日
    ''' </summary>
    Public NotInheritable Class WeekDayType : Inherits ConstantItem
        
        Public Shared ReadOnly Items As New ConstantItemCollection(Of WeekDayType)

        Public Shared ReadOnly Sun As New WeekDayType(1, "日曜日", "日")
        Public Shared ReadOnly Mon As New WeekDayType(2, "月曜日", "月")
        Public Shared ReadOnly Tue As New WeekDayType(3, "火曜日", "火")
        Public Shared ReadOnly Wed As New WeekDayType(4, "水曜日", "水")
        Public Shared ReadOnly Thr As New WeekDayType(5, "木曜日", "木")
        Public Shared ReadOnly Fri As New WeekDayType(6, "金曜日", "金")
        Public Shared ReadOnly Sat As New WeekDayType(7, "土曜日", "土")

        Private Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            MyBase.new(cd, name, aliasname)
            Items.Add(Me)
        End Sub

    End Class
End Namespace

ConstantItemCollectionクラス
定数を追加するためのコレクションクラスです。
ConstantItemまたはその派生クラスのみを格納できるListクラスです。
コンボボックスのDataSouceに設定する際、コピーーできるようICloneableインタフェースを実装します。
Namespace Constant
Namespace Constant
    ''' <summary>
    ''' 定数アイテムを管理するコレクションクラスです。
    ''' </summary>
    Public Class ConstantItemCollection(Of T As ConstantItem)
        Inherits List(Of T)
        Implements ICloneable
        
        ''' <summary>
        ''' 定義されている定数アイテムより、引数に指定したcdをもつアイテムを検索します。
        ''' </summary>
        Public Function GetItem(ByVal cd As Integer) As T
            For idx As Integer = 0 To Me.Count - 1
                If cd = CType(Me.Item(idx), ConstantItem).Cd Then
                    Return CType(Me.Item(idx), T)
                End If
            Next
            Return Nothing
        End Function

        ''' <summary>
        ''' 定義されている定数アイテムより、引数に指定したnameをもつアイテムを検索します。
        ''' </summary>
        Public Function GetItem(ByVal name As String) As T
            For idx As Integer = 0 To Me.Count - 1
                If name = CType(Me.Item(idx), ConstantItem).Name Then
                    Return CType(Me.Item(idx), T)
                End If
            Next
            Return Nothing
        End Function
        
        ''' <summary>
        ''' Copyメソッド
        ''' </summary>
        Public Function Copy() As ConstantItemCollection(Of T)
            Return DirectCast(Me.Clone(), ConstantItemCollection(Of T))
        End Function

        '-----ICloneableインターフェースのimplementsメソッド-----

        ''' <summary>
        ''' Cloneメソッド
        ''' </summary>
        Private Function Clone() As Object Implements System.ICloneable.Clone
            '戻り値がObject型だと不便なのでPrivateにしCopyメソッドをPublicで公開します。
            Return Me.MemberwiseClone()
        End Function
        
    End Class
End Namespace

ConstantItemクラスはToStringメソッドをオーバーライドしました。
Namespace Constant

    ''' <summary>
    ''' 定数アイテムの基底クラスです。
    ''' </summary>
    Public MustInherit Class ConstantItem

        '-----フィールド-----

        ''' <summary>コード</summary>
        Protected _iCd As Integer
        ''' <summary>名前</summary>
        Protected _sName As String
        ''' <summary>別名</summary>
        Protected _sAliasName As String

        '-----Publicプロパティ-----

        ''' <summary>コードを取得します</summary>
        Public ReadOnly Property Cd() As Integer
            Get
                Return Me._iCd
            End Get
        End Property
        ''' <summary>名前を取得します。</summary>
        Public ReadOnly Property Name() As String
            Get
                Return Me._sName
            End Get
        End Property
        ''' <summary>別名を取得します。</summary>
        Public ReadOnly Property AliasName() As String
            Get
                Return Me._sAliasName
            End Get
        End Property

        '-----コンストラクタ-----

        ''' <summary>引数を取らないコンストラクタ</summary>
        Private Sub New()
        End Sub
        ''' <summary>コードと名前を引数に取るコンストラクタ</summary>
        Public Sub New(ByVal cd As Integer, ByVal name As String)
            MyBase.New()
            Me._iCd = cd
            Me._sName = name
        End Sub
        ''' <summary>コードと名前と別名を引数に取るコンストラクタ</summary>
        Public Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            Me.New(cd, name)
            Me._sAliasName = aliasname
        End Sub
        
        '-----Public Overridesメソッド-----

        ''' <summary>
        ''' ToStringメソッド
        ''' </summary>
        Public Overrides Function ToString() As String
            Return String.Format("Cd={0},Nmae={1},AliasName={2}", Me._iCd, Me._sName, Me._sAliasName)
        End Function

    End Class
End Namespace

テストコードです。
フォームにコンボボックスを2つとボタンを1つ配置し、以下のコードを実行します。
Public Class Form1

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'コンボボックス1にWeekDayTypeの定数リストを設定します。
        Me.ComboBox1.ValueMember = "Cd"
        Me.ComboBox1.DisplayMember = "Name"
        Me.ComboBox1.DataSource = Constant.WeekDayType.Items
        
         'コンボボックス2にWeekDayTypeの定数リストを設定します。
         '※Copyを設定しないとコンボボックス1と連動してしまいます。
        Me.ComboBox2.ValueMember = "Cd"
        Me.ComboBox2.DisplayMember = "Name"
        Me.ComboBox2.DataSource = Constant.WeekDayType.Items.Copy
    End Sub

    Private Sub ComboBox1_SelectedValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedValueChanged
        'コンボボックスで選択されているWeekDayTypeオブジェクトを取得します。
        Dim weekday As Constant.WeekDayType
        weekday = DirectCast(Me.ComboBox1.SelectedItem, Constant.WeekDayType)
        Console.WriteLine(weekday)
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'Cd=2のWeekDayTypeオブジェクトを取得します。
        Dim iWeekDayCd As Integer = 2
        Dim weekday As Constant.WeekDayType = Constant.WeekDayType.Items.GetItem(iWeekDayCd)
        Console.WriteLine(weekday)
    End Sub

End Class

.NET 定数ファイルを作成する ~その4~ インテリセンスに候補を表示する

.NET 定数ファイルを作成する ~その1~
.NET 定数ファイルを作成する ~その2~
.NET 定数ファイルを作成する ~その3~

列挙体に文字列を持たせたいときに、クラスに定数メンバを並べて代用しています。

Namespace Constant

    ''' <summary>
    ''' 曜日
    ''' </summary>
    Public NotInheritable Class WeekDayType : Inherits ConstantItem

        Public Shared ReadOnly Sun As New WeekDayType(1, "日曜日", "日")
        Public Shared ReadOnly Mon As New WeekDayType(2, "月曜日", "月")
        Public Shared ReadOnly Tue As New WeekDayType(3, "火曜日", "火")
        Public Shared ReadOnly Wed As New WeekDayType(4, "水曜日", "水")
        Public Shared ReadOnly Thr As New WeekDayType(5, "木曜日", "木")
        Public Shared ReadOnly Fri As New WeekDayType(6, "金曜日", "金")
        Public Shared ReadOnly Sat As New WeekDayType(7, "土曜日", "土")

        Private Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            MyBase.new(cd, name, aliasname)
        End Sub

    End Class
End Namespace

Namespace Constant

    ''' <summary>
    ''' 定数アイテムの基底クラスです。
    ''' </summary>
    Public MustInherit Class ConstantItem

        '-----フィールド-----

        ''' <summary>コード</summary>
        Protected _iCd As Integer
        ''' <summary>名前</summary>
        Protected _sName As String
        ''' <summary>別名</summary>
        Protected _sAliasName As String

        '-----Publicプロパティ-----

        ''' <summary>コードを取得します</summary>
        Public ReadOnly Property Cd() As Integer
            Get
                Return Me._iCd
            End Get
        End Property
        ''' <summary>名前を取得します。</summary>
        Public ReadOnly Property Name() As String
            Get
                Return Me._sName
            End Get
        End Property
        ''' <summary>別名を取得します。</summary>
        Public ReadOnly Property AliasName() As String
            Get
                Return Me._sAliasName
            End Get
        End Property

        '-----コンストラクタ-----

        ''' <summary>引数を取らないコンストラクタ</summary>
        Private Sub New()
        End Sub
        ''' <summary>コードと名前を引数に取るコンストラクタ</summary>
        Public Sub New(ByVal cd As Integer, ByVal name As String)
            MyBase.New()
            Me._iCd = cd
            Me._sName = name
        End Sub
        ''' <summary>コードと名前と別名を引数に取るコンストラクタ</summary>
        Public Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            Me.New(cd, name)
            Me._sAliasName = aliasname
        End Sub
        
    End Class
End Namespace

使用方法は以下のようになります。
Dim w As Constant.WeekDayType = Constant.WeekDayType.Fri

しかし列挙体であれば「=」を入力した時点でインテリセンスに候補がでますが、


自作のクラスでは「 Constant.WeekDayType.」まで入力しないとインテリセンスに候補が表示されません。



けれどSystem.Drawing.Color構造体は列挙体と同じように「=」を入力した時点で、Public Sharedなメンバがインテリセンスの候補に表示されます。




System.Drawing.Color構造体と同じようにWeekDayTypeクラスも「=」を入力した時点でインテリセンスに候補が表示されるように変更します。
WeekDayTypeクラスに <completionlist cref="クラス名"/> をつけるだけです。
Namespace Constant

    ''' <summary>
    ''' 曜日
    ''' </summary>
    ''' <completionlist cref="WeekDayType"/>
    Public NotInheritable Class WeekDayType : Inherits ConstantItem

        Public Shared ReadOnly Sun As New WeekDayType(1, "日曜日", "日")
        Public Shared ReadOnly Mon As New WeekDayType(2, "月曜日", "月")
        Public Shared ReadOnly Tue As New WeekDayType(3, "火曜日", "火")
        Public Shared ReadOnly Wed As New WeekDayType(4, "水曜日", "水")
        Public Shared ReadOnly Thr As New WeekDayType(5, "木曜日", "木")
        Public Shared ReadOnly Fri As New WeekDayType(6, "金曜日", "金")
        Public Shared ReadOnly Sat As New WeekDayType(7, "土曜日", "土")

        Private Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            MyBase.new(cd, name, aliasname)
        End Sub

    End Class
End Namespace
これで
Dim w As Constant.WeekDayType = の「=」を入力した時点でインテリセンスに候補が表示されるようになります。