コンボボックスに複数列を表示させるには

※複数列コンボボックス:マルチカラムコンボボックスともいう

『データと連結したコントロールの配置方法』の、Bコンボボックスの設定でも解説していますが、Visual Studio 2005標準のコンボボックスで表示できる項目(フィールド)は1つだけです。
担当者名などを表示する場合はそれで良いのかもしれませんが、実際のアプリケーションでは複数項目を表示したいことはよくあります。
そこで、Visual Studio 2005のComboBoxコントロールにある、[DrawMode]プロパティとDrawItemイベントに注目します。
標準コンボボックスの[DrawMode]プロパティは、展開したリスト(コンボボックスのドロップダウンボタンが押された時に表示されるデータのこと)の描画を.NETシステムで処理するか、自分で用意したプログラムで独自処理するかを選択するためのプロパティです。
この値を『OwnerDrawFixed』にすることによって、コンボボックスを展開した時にDrawItemイベントが発生し、記述したプログラムを元に展開されたリストを独自に描画します。描画、すなわちフォントの指定、背景色、境界線までもを独自に設定することができるのです。
※コンボボックス内にイメージを表示することもできます。

DrawItemイベントは、ユーザーがコンボボックスを展開した時にDataSourceに指定したオブジェクトのデータを1行分画面に表示するごとに発生します。たとえば、コンボボックスを開いて、データが10行表示されるとすれば、DrawItemイベントは10回発生しているということになります。

実際に[得意先C]ConboBoxに複数列を表示したい場合のコードを記述する際は、以下の手順となります。

@フォームのLoadイベントに、以下の記述を追加します。

'******↓この部分もコピーすること
Private
Const COLUMN_MARGIN A sInteger = 2
Private Const ITEM_COUNT As Integer = 7
Private haba(ITEM_COUNT - 1) As SizeF
'表示幅の算出
Private Function upGetHabaTotal() As Integer
    Dim intDropDownWidth As Integer, i As Integer
    intDropDownWidth = 0
    For i = 0 To ITEM_COUNT - 1
        intDropDownWidth += haba(i).Width
    Next
    Return intDropDownWidth
End Function
'******↑この部分もコピーすること

Private Sub frmUriage_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) HandlesMyBase.Load

           
(略)

    WithMe.cmb得意先C
        'オーナードローモードを指定
        .DrawMode = DrawMode.OwnerDrawFixed
        '表示スタイル指定
        .DropDownStyle = ComboBoxStyle.DropDown
        '項目幅をそれぞれ決定
    '得意先C
        haba(0) = Me.CreateGraphics.MeasureString(StrDup(8, "#"), Me.Font)
     '得意先名
        haba(1) = Me.CreateGraphics.MeasureString(StrDup(30, "#"), Me.Font)
     'ふりがな(非表示)
        haba(2) = Me.CreateGraphics.MeasureString(StrDup(0, "#"), Me.Font)
    '税計算法(非表示)

        haba(3) = Me.CreateGraphics.MeasureString(StrDup(0, "#"), Me.Font)
    '金額端数処理(非表示

        haba(4) = Me.CreateGraphics.MeasureString(StrDup(0, "#"), Me.Font)
    '消費税端数処理(非表示)
        haba(5) = Me.CreateGraphics.MeasureString(StrDup(0, "#"), Me.Font)
    '締日

        haba(6) = Me.CreateGraphics.MeasureString(StrDup(4, "#"), Me.Font)
        '幅にマージン分を追加(表示分のみ)
        Dim i As Integer
        For i = 0 To ITEM_COUNT - 1
            If haba(i).Width <> 0 Then haba(i).Width += COLUMN_MARGIN * 2
        Next
        'ドロップダウンリスト幅の指定
        .DropDownWidth = upGetHabaTotal()
    End With
End Sub

A [得意先C]のDrawItemイベントに、以下の記述を行う。
★以下をコピーして貼り付けるだけでよい!!

Private Sub cmb得意先C_DrawItem( _
    ByVal sender As Object, _
    ByVal e As System.Windows.Forms.DrawItemEventArgs) _
  Handles cmb
得意先C.DrawItem

    'このプログラムはコンボボックスが開かれない限りは実行されない
    'このプログラムはコンボボックスのリストを1行ずつ表示する際にその都度実行される
   
Dim i As Integer

    Try
        '境界線の位置
        Dim asngSP(ITEM_COUNT - 1) As Single
        For i = 0 To ITEM_COUNT - 1
            If i = 0 Then asngSP(i) = 0 Else asngSP(i) = asngSP(i - 1)
            If haba(i).Width <> 0 Then asngSP(i) += haba(i).Width
        Next i
        'コンボボックスリストの生成
        'リスト1行分の位置データを構造体へ格納する
        Dim rec As New Rectangle(e.Bounds.X, e.Bounds.Y,upGetHabaTotal,e.Bounds.Height)
        'リストの背景色を描画
       If Me.Enabled Then
            'コンボボックスの使用可能がオンの場合
            If CBool(e.State And DrawItemState.Selected) Then
                'カーソルがある行はハイライト
                e.Graphics.FillRectangle(New SolidBrush(System.Drawing.SystemColors.Highlight), rec)
            Else
                'それ以外は白
                e.Graphics.FillRectangle(New SolidBrush(System.Drawing.SystemColors.Window), rec)
            End If
        Else
            'コンボボックスの使用可能がオフの場合、列をグレーアウトする
            e.Graphics.FillRectangle(New SolidBrush(System.Drawing.SystemColors.Control), rec)
        End If
        'リストの内容を描画
        '(セルのコンボボックスのDetaSourceより、各項目名を書き込む)
        If e.Index > -1 Then
            Dim recColumn As Rectangle, strItemValue As String
            Dim obj As Object = sender.Items(e.Index)
            For i = 0 To ITEM_COUNT - 1
                If haba(i).Width <> 0 Then
                    '各項目の位置情報を設定
                    If i = 0 Then
                        recColumn = New Rectangle(COLUMN_MARGIN, e.Bounds.Y, haba(i).Width, e.Bounds.Height)
                    Else
                        recColumn = New Rectangle(asngSP(i - 1) + COLUMN_MARGIN, e.Bounds.Y, haba(i).Width, e.Bounds.Height)
                   End If
                  
'
文字描画
                    strItemValue = obj(i).ToString
                    If CBool(e.State And DrawItemState.Selected) Then
                        'カーソルがある行はハイライト
                        e.Graphics.DrawString( _
                            strItemValue, e.Font, _
                            New SolidBrush(System.Drawing.SystemColors.HighlightText), recColumn)

                    Else
                        'それ以外は標準(黒)
                        e.Graphics.DrawString( _
                            strItemValue, e.Font, _
                            New SolidBrush(System.Drawing.SystemColors.ControlText), recColumn)

                   End If
                    '境界線描画
                    e.Graphics.DrawLine( _
                        New Pen(System.Drawing.SystemColors.ControlDark), _
                        asngSP(i), e.Bounds.Top, asngSP(i), e.Bounds.Bottom)

                End If
            Next
        Else
            'データが無い場合
            e.Graphics.DrawString("", e.Font, New SolidBrush(System.Drawing.SystemColors.ControlText), rec)
        End If
    Catch ex As Exception
    End Try
End Sub

以上の設定だけで複数列表示のコンボボックスが出来上がります。
動作させてみると分かりますが、Accessコンボボックスのように先頭一致で頭だしを行なう機能も自動的に実現されています。

<<以上、ドキュメントより抜粋>>

※ソースのスペース等が抜けている場合があります。
※ここでは[cmb得意先C]コンボボックスのDataSourceが設定済みであることを前提としています。


有限会社ビット