.NET Frameworkのクラスライブラリに含まれるSystem.Windows.Forms.ListBoxクラスは、VB6以前のListBoxが機能拡張されたものと言えます。 というのも、多くの動作はそのままで様々な機能が追加されているからです。 ここではそのような追加された機能を見ていきたいと思います。
選択されているアイテムとインデックスの取得
まずは、選択されているアイテムと、そのインデックスの取得について見てみます。 リストボックスのアイテムの内、選択されているものはSelectedItemsプロパティ、そのインデックスはSelectedIndicesプロパティによって取得できます。 これらのプロパティは IEnumerableインターフェイスを実装したコレクションになっているので、For Each文によって列挙できます。
次のサンプルは、インデックスと同じ値を振った文字列アイテムをリストボックスに追加し、選択されているアイテムが変わったときに生じるSelectedValueChangedイベントで選択されているアイテムとそのインデックスを列挙しています。
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows フォーム デザイナで生成されたコード "
#End Region
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
With listBoxItems
' 選択モード
.SelectionMode = SelectionMode.MultiExtended
With .Items
Dim i As Integer
For i = 0 To 9
.Add("Item" + i.ToString())
Next
End With
End With
End Sub
Private Sub listBoxItems_SelectedValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles listBoxItems.SelectedValueChanged
' 選択されているアイテム一覧を表示
Dim o As Object
listBoxSelectedItems.Items.Clear()
For Each o In listBoxItems.SelectedItems
listBoxSelectedItems.Items.Add(o)
Next
' 選択されているアイテムのインデックス一覧を表示
Dim i As Integer
listBoxSelectedIndices.Items.Clear()
For Each i In listBoxItems.SelectedIndices
listBoxSelectedIndices.Items.Add(i)
Next
End Sub
End Class

様々な型のアイテムの追加
リストボックスには、様々な型のアイテムを追加することもできます。 というのも、アイテムのコレクションはすべての型の基底クラスであるObject型でアイテムを扱っているのためです。 また、文字列以外の型をアイテムとして追加すると、その場合はToString()メソッドによって得られる文字列がリストボックスに表示される文字列となります。
次のコードで様々な型のアイテムを追加し、どのように表示されるかを検証してみます。
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows フォーム デザイナで生成されたコード "
#End Region
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
With listBoxItems
' 選択モード
.SelectionMode = SelectionMode.MultiExtended
' 様々な型のアイテムを追加
With .Items
.Add(123456)
.Add(3.14159265358)
.Add("文字列")
.Add(Color.Red)
.Add(SortOrder.Ascending)
.Add(New Point(320, 240))
.Add(New ArrayList())
.Add(New Pen(Color.Cyan))
End With
End With
End Sub
Private Sub listBoxItems_SelectedValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles listBoxItems.SelectedValueChanged
' 選択されているアイテム一覧を表示
Dim o As Object
listBoxSelectedItems.Items.Clear()
For Each o In listBoxItems.SelectedItems
listBoxSelectedItems.Items.Add(o)
Next
' 選択されているアイテムのインデックス一覧を表示
Dim i As Integer
listBoxSelectedIndices.Items.Clear()
For Each i In listBoxItems.SelectedIndices
listBoxSelectedIndices.Items.Add(i)
Next
End Sub
End Class

アイテム並べ替えのカスタマイズ
SortedプロパティをTrueに指定すると、表示されている文字のアルファベット順でアイテムが並べ替えられます。 多くの場合はアルファベット順でも問題ないのですが、文字列型以外の型をアイテムとして格納しているとき、アルファベット順では不適切な場合が生じてきます。 そこで、アルファベット順ではない独自の並べ替えを行ってみたいと思います。 そのためにはArrayListのAdapter()メソッドを利用します。
このメソッドは、IListインターフェイスに対してそれをラップするArrayListのラッパーを作成します。 つまり、 IListが実装していないSort()メソッドをArrayListにラップさせることで利用することができるようになります。 Sort()メソッドでは比較子を何も指定しないとデフォルトでアルファベット順に並べ替えられますが、IComparerを実装したクラスのインスタンスを引数に与えると、独自に定義した並べ替えを行わせることができます。
次のコードでは、Point型のアイテムをあらかじめリストボックスに追加しておき、その後でArrayListのラッパーを作成して並べ替えを行います。 並べ替え順を定義するクラスはPointComparerで、このクラスではPoint型変数のYプロパティの値によって並べ替えを行います。 参考までに、SortedプロパティをTrueにしたときの実行結果も添えておきます。
' 独自の並べ替えを定義するクラス
Public Class PointComparer
Implements IComparer
' 座標値による比較
Public Function Compare(ByVal objX As Object, ByVal objY As Object) As Integer Implements IComparer.Compare
If objX Is Nothing Then Return 1
If objY Is Nothing Then Return -1
Dim ptX As Point = CType(objX, Point)
Dim ptY As Point = CType(objY, Point)
If ptX.Y = ptY.Y Then
' Yの値が等しいときは、座標は等しいと見なす
Return 0
ElseIf ptX.Y > ptY.Y Then
' Yの値が大きいときは、座標は大きいと見なす
Return 1
Else
' それ以外の場合は、座標は小さいと見なす
Return -1
End If
End Function
End Class
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows フォーム デザイナで生成されたコード "
#End Region
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
With listBoxItems
' 選択モード
.SelectionMode = SelectionMode.MultiExtended
' Point型のアイテムを追加
With .Items
.Add(New Point(320, 240))
.Add(New Point(173, 141))
.Add(New Point(640, 480))
.Add(New Point(320, 200))
.Add(New Point(141, 173))
.Add(New Point(480, 640))
.Add(New Point(320, 240))
.Add(New Point(640, 480))
.Add(New Point(480, 360))
.Add(New Point(141, 141))
End With
' ArrayListアダプタによる並べ替え
Dim arr As ArrayList = ArrayList.Adapter(.Items)
arr.Sort(New PointComparer())
End With
End Sub
End Class


DataSourceプロパティによるアイテムの指定
リストボックスのDataSourceプロパティにIListインターフェイスを実装したオブジェクト(ArrayやDataSetオブジェクト)を指定すると、Itemsプロパティからアイテムを追加しなくても、アイテムを表示させることができます。 つまり、既存の配列やコレクションをアイテムとしてリストボックスに表示できるのです。
DataSourceプロパティにIListインターフェイスを実装したオブジェクトを指定した場合は、DisplayMember及びValueMemberプロパティも指定する必要があります。 DisplayMemberプロパティには、コレクションに含まれるオブジェクトのプロパティのうち、リストボックスに表示するべきプロパティの名前を指定します。 同様に、ValueMemberプロパティにはアイテムを指定する時に用いるプロパティ名を指定します。 ここで、DataSourceプロパティに値を設定した場合は、Itemsプロパティによってアイテムに対する操作を行うことはできません。
次のコードでは、NickNameとFullNameという二つのプロパティを持ったMusumeクラスのオブジェクトを ArrayListオブジェクトに格納し、それをリストボックスのDataSourceプロパティに指定しています。 また、リストボックスの DisplayMemberプロパティにはMusumeクラスのFullNameプロパティ、ValueMemberプロパティにはMusumeクラスの NickNameプロパティを指定しています。
' アイテムとしてリストボックスに追加されるクラス
Public Class Musume
Private m_NickName As String
Private m_FullName As String
Public Sub New(ByVal nickName As String, ByVal fullName As String)
m_NickName = nickName
m_FullName = fullName
End Sub
Public ReadOnly Property NickName() As String
Get
Return m_NickName
End Get
End Property
Public ReadOnly Property FullName() As String
Get
Return m_FullName
End Get
End Property
Public Overrides Function ToString() As String
Return m_FullName + "(" + m_NickName + ")"
End Function
End Class
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows フォーム デザイナで生成されたコード "
#End Region
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' 元となるデータ
Dim arr As New ArrayList()
With arr
.Add(New Musume("あいぼん", "加護亜依"))
.Add(New Musume("チャーミー", "石川梨華"))
.Add(New Musume("なっち", "安部なつみ"))
.Add(New Musume("ミキティ", "藤本美貴"))
.Add(New Musume("こんこん", "紺野あさ美"))
End With
With listBoxItems
' 選択モード
.SelectionMode = SelectionMode.MultiExtended
' 元となるデータを設定
.DataSource = arr
' リストボックスに表示されるプロパティ
.DisplayMember = "FullName"
' アイテムを指定する時に用いるプロパティ
.ValueMember = "NickName"
' すべての選択を解除
.ClearSelected()
' いくつかのアイテムを、ValueMenberで指定したプロパティにより指定
.SelectedValue = "チャーミー"
.SelectedValue = "ミキティ"
' この操作はできない
' DataSourceに元となるデータを指定しているときは、直接アイテムを操作できない
'.Items.Add(New Musume("まりっぺ", "矢口真里"))
End With
End Sub
End Class

この結果を見てわかるとおり、リストボックスにはFullNameプロパティの値で表示され、ソースコードでアイテムを選択する場合はNickNameプロパティの値を用いています。
また、DataSourceプロパティを指定していない他のリストボックスで選択されているアイテムを表示しようとすると次のようになります。 つまり、ToString()メソッドによって得られる文字列をアイテムとして表示します。
