2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【VB.NET、C#】表示名と値が異なるコンボボックス

Posted at

コンボボックスの表示名と実際の値を分けたい場合、次の2パターンの方法がポピュラーです。

  • Items.Addで作成
  • DataSourceで作成

動作確認用に簡単な画面を用意しました。
20211227_001.jpg

画面仕様はとても簡単です。

  • 左のコンボボックス…選択可能
  • 右のテキストボックス…コンボボックスで選択されたアイテムの実際の値を表示

コンボボックスが選択されるとこうなります。

20220104_001.jpg

#Items.Addで作成する場合
まずは、Items.Addで作成する方法。

【必要なモノ】

  • フォームとコンボボックス(当たり前)
  • コンボボックス用の独自クラス

フォームとコンボボックスは先ほどの画像の通り。
コンボボックス用の独自クラスは次の様に作成します。

'【VB.NET】
'コンボボックス用の独自クラス
Public Class MyItems
    'クラス変数
    Private m_Code As String = ""
    Private m_Name As String = ""

    'コンストラクタ
    Public Sub New(ByVal strCode As String, ByVal strName As String)
        m_Code = strCode
        m_Name = strName
    End Sub

    'プロパティ(実際の値)
    Public ReadOnly Property Code() As String
        Get
            Return m_Code
        End Get
    End Property

    'プロパティ(表示する名称)
    Public ReadOnly Property Name() As String
        Get
            Return m_Name
        End Get
    End Property

    'コンボボックス表示用メソッド(ToStringのオーバーライド)
    Public Overrides Function ToString() As String
        Return m_Name
    End Function
End Class

//【C#】
//コンボボックス用の独自クラス
class MyItems
{
    private string m_Code = "";
    private string m_Name = "";

    //コンストラクタ
    public MyItems(string strCode, string strName)
    {
        m_Code = strCode;
        m_Name = strName;
    }

    //プロパティ(実際の値)
    public string Code
    {
        get
        {
            return m_Code;
        }
    }

    //プロパティ(表示する名称)
    public string Name
    {
        get
        {
            return m_Name;
        }
    }

    //コンボボックス表示用メソッド(ToStringのオーバーライド)
    public override string ToString()
    {
        return m_Name;
    }
}

クラスを用意したら、次はフォーム画面のコード作成。

'【VB.NET】
'画面
Public Class Form_ComboBox
    Private Sub Form_ComboBox_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim objItem As MyItems

        '要素を独自クラスにセット①
        objItem = New MyItems("01", "北海道")

        'コンボボックスにセット②
        cmbTest.Items.Add(objItem)

        '要素を独自クラスにセット②
        objItem = New MyItems("02", "青森県")

        'コンボボックスにセット②
        cmbTest.Items.Add(objItem)

        '要素を独自クラスにセット②
        objItem = New MyItems("03", "岩手県")

        'コンボボックスにセット②
        cmbTest.Items.Add(objItem)
    End Sub

    'SelectedIndexChangedイベント
    Private Sub cmbTest_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbTest.SelectedIndexChanged
        If cmbTest.SelectedIndex <> -1 Then

            Dim objItem As MyItems

            objItem = DirectCast(cmbTest.SelectedItem, MyItems)

            '選択中のコード値をテキストボックスに表示
            txtCode.Text = objItem.Code

        End If
    End Sub
End Class

//【C#】
//画面
public partial class Form_ComboBox : Form
{
    public Form_ComboBox()
    {
        InitializeComponent();
    }

    private void Form_ComboBox_Load(object sender, EventArgs e)
    {
        MyItems objItem;

        //要素を独自クラスにセット①
        objItem = new MyItems("01", "北海道");

        //コンボボックスにセット①
        cmbTest.Items.Add(objItem);

        //要素を独自クラスにセット②
        objItem = new MyItems("02", "青森県");

        //コンボボックスにセット②
        cmbTest.Items.Add(objItem);

        //要素を独自クラスにセット③
        objItem = new MyItems("03", "岩手県");

        //コンボボックスにセット③
        cmbTest.Items.Add(objItem);
    }

    //SelectedIndexChangedイベント
    private void cmbTest_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (cmbTest.SelectedIndex != -1)
        {
            MyItems item;

            //選択中のアイテムのオブジェクトを取得
            item = (MyItems)cmbTest.SelectedItem;

            //Idプロパティをラベルに表示
            txtCode.Text = item.Code;
        }
    }
}

察しの良い方は既に分かると思いますが、コンボボックスに要素を1つずつ追加しています。
こんなこと、実際の現場ではなかなか見ません。
実際はSQLの結果や外部ファイルの値をコンボボックスに設定します。

なので、今回はCSVをインポートしてループ処理でコンボボックスの表示名と値を設定します。

'【VB.NET】
Imports System.Text     'CSVインポートで利用

Public Class Form_ComboBox
    Private Sub Form_ComboBox_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        'CSVファイル
        Dim strFilePath As String = "D:\temp\Combo\todohuken.csv"

        'CSVインポート
        Using objIoTFP As New Microsoft.VisualBasic.FileIO.TextFieldParser(strFilePath, Encoding.GetEncoding("Shift_JIS"))
            '読み込み時の設定
            With objIoTFP
                '区切り文字をカンマに設定
                .TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
                .SetDelimiters(",")
                '空白があった場合にTrimしない
                .TrimWhiteSpace = False
            End With

            'コンボボックス用クラス
            Dim objItem As MyItems

            'CSV読み込み実行
            While Not objIoTFP.EndOfData
                'CSVの1行を配列にセット
                Dim arrayRow As String() = objIoTFP.ReadFields()
                '要素を独自クラスにセット
                objItem = New MyItems(arrayRow(0), arrayRow(1))
                'コンボボックスにセット
                cmbTest.Items.Add(objItem)
            End While
        End Using
    End Sub

    'SelectedIndexChangedイベント
    Private Sub cmbTest_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbTest.SelectedIndexChanged
        If cmbTest.SelectedIndex <> -1 Then

            Dim objItem As MyItems

            objItem = DirectCast(cmbTest.SelectedItem, MyItems)

            '選択中のコード値をテキストボックスに表示
            txtCode.Text = objItem.Code

        End If
    End Sub
End Class

//【C#】
using Microsoft.VisualBasic.FileIO;     //CSVインポートで利用

public partial class Form_ComboBox : Form
{
    public Form_ComboBox()
    {
        InitializeComponent();
    }

    private void Form_ComboBox_Load(object sender, EventArgs e)
    {
        string strFilePath = "D:/temp/Combo/todohuken.csv";

        //TextFieldParserのインスタンス生成
        var objParser = new TextFieldParser(strFilePath, Encoding.GetEncoding("Shift_JIS"));

        using (objParser)
        {
            //読み込み時の設定
            //区切り文字をカンマ指定
            objParser.TextFieldType = FieldType.Delimited;
            objParser.SetDelimiters(",");

            //空白があった場合にTrimしない
            objParser.TrimWhiteSpace = false;

            //コンボボックス用クラス
            MyItems objItem;

            //CSV読み込み実行
            while (!objParser.EndOfData)
            {
                // CSVの1行を配列にセット
                string[] arrayRow = objParser.ReadFields();
                // 要素を独自クラスにセット
                objItem = new MyItems(arrayRow[0], arrayRow[1]);
                //コンボボックスにセット
                cmbTest.Items.Add(objItem);
            }
            
        }
    }

    private void cmbTest_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (cmbTest.SelectedIndex != -1)
        {
            MyItems item;

            //Load時に追加したオブジェクトの中から選択中のものを取得
            item = (MyItems)cmbTest.SelectedItem;

            //Idプロパティをラベルに表示
            txtCode.Text = item.Code;
        }
    }
}

#DataSourceで作成する場合
次にDataSourceで作成する方法。

【必要なモノ】

  • フォームとコンボボックス(当たり前)

フォームとコンボボックスは先ほどの画像の通り。
以下の順序でコンボボックスのDataSourceに表示名と実際の値を格納します。

  1. フォームロード時にCSVをインポート
  2. CSVデータを配列に格納(実際の値、表示名)し、その配列をリストに格納
  3. リストを走査してDataTableを作成
  4. DataTableをコンボボックスのDataSourceにセット

尚、CSVインポート時にJet Providerで一気にDataTableを作成できますが、「配列からDataTableを作ってDataSourceにセットする」というステップを踏みたいので、敢えてTextFieldParserでのCSVインポートを実施しています。
※各現場で環境や制約が異なると思いますが、配列からDataTableが作成できないという現場は流石に無いと思いますので。

'【VB.NET】
Imports System.Text     'CSVインポートで利用
Public Class Form_ComboBox_DataTable
    Private Sub Form_ComboBox_DataTable_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        'CSVファイル
        Dim strFilePath As String = "D:\temp\Combo\todohuken.csv"

        '配列格納用リスト
        Dim strListDT As List(Of String()) = New List(Of String())
        'データテーブルの用意
        Dim objDT As New DataTable()
        objDT.Columns.Add("Code", GetType(String))      '実際の値
        objDT.Columns.Add("Name", GetType(String))      '表示名

        'CSVインポート
        Using objIoTFP As New Microsoft.VisualBasic.FileIO.TextFieldParser(strFilePath, Encoding.GetEncoding("Shift_JIS"))
            '読み込み時の設定
            With objIoTFP
                '区切り文字をカンマに設定
                .TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
                .SetDelimiters(",")
                '空白があった場合にTrimしない
                .TrimWhiteSpace = False
            End With

            'CSV読み込み実行
            While Not objIoTFP.EndOfData
                'CSVの1行を配列にセット
                Dim arrayRow As String() = objIoTFP.ReadFields()
                '配列格納用リストにセット
                strListDT.Add(arrayRow)
            End While
        End Using

        'データテーブルの作成
        For Each strArray As String() In strListDT
            'データテーブル用の行オブジェクトを作成
            Dim objDR As DataRow = objDT.NewRow()
            objDR("Code") = strArray(0)    '実際の値(ValueMember)
            objDR("Name") = strArray(1)    '表示名(DisplayMember)

            '配列格納用リストに行オブジェクトを格納
            objDT.Rows.Add(objDR)
        Next

        'データテーブルのコミット
        objDT.AcceptChanges()
        'データテーブルをコンボボックスのデータソースにセット
        cmbTest.DataSource = objDT

        'ValueMemberとDisplayMemberを設定
        cmbTest.ValueMember = "Code"    '実際の値
        cmbTest.DisplayMember = "Name"  '表示名
    End Sub

    'SelectedIndexChangedイベント()
    Private Sub cmbTest_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbTest.SelectedIndexChanged
        If cmbTest.SelectedIndex <> -1 Then
            '選択中のコード値をテキストボックスに表示
            txtCode.Text = cmbTest.SelectedValue.ToString()
        End If
    End Sub
End Class

//【C#】
using Microsoft.VisualBasic.FileIO;     //CSVインポートで利用

namespace CS_ComboBox_DataTable
{
    public partial class Form_ComboBox_DataTable : Form
    {
        public Form_ComboBox_DataTable()
        {
            InitializeComponent();
        }

        private void Form_ComboBox_DataTable_Load(object sender, EventArgs e)
        {
            //CSVファイル
            string strFilePath = "D:/temp/Combo/todohuken.csv";

            //配列格納用リスト
            List<String[]> strListDT = new List<String[]>();
            //データテーブルの用意
            DataTable objDT = new DataTable();
            objDT.Columns.Add("Code", typeof(String));      //実際の値
            objDT.Columns.Add("Name", typeof(String));      //表示名

            //TextFieldParserのインスタンス生成
            var objParser = new TextFieldParser(strFilePath, Encoding.GetEncoding("Shift_JIS"));

            using (objParser)
            {
                // 読み込み時の設定
                // 区切り文字をカンマ指定
                objParser.TextFieldType = FieldType.Delimited;
                objParser.SetDelimiters(",");

                // 空白があった場合にTrimしない
                objParser.TrimWhiteSpace = false;

                // CSV読み込み実行
                while (!objParser.EndOfData)
                {
                    // CSVの1行を配列にセット
                    string[] arrayRow = objParser.ReadFields();
                    //リストにセット
                    strListDT.Add(arrayRow);
                }

            }

            //データテーブルの作成
            foreach(string[] strArray in strListDT)
            {
                //データテーブル用の行オブジェクトを作成
                DataRow objDR = objDT.NewRow();
                objDR["Code"] = strArray[0];    //実際の値(ValueMember)
                objDR["Name"] = strArray[1];    //表示名(DisplayMember)

                //配列格納用リストに行オブジェクトを格納
                objDT.Rows.Add(objDR);
            }

            //データテーブルのコミット
            objDT.AcceptChanges();
            //データテーブルをコンボボックスのデータソースにセット
            cmbTest.DataSource = objDT;

            //ValueMemberとDisplayMemberを設定
            cmbTest.ValueMember = "Code";
            cmbTest.DisplayMember = "Name";
        }

        private void cmbTest_SelectedIndexChanged(object sender, EventArgs e)
        {
            //選択されていればSelectedValueに入っている
            if (cmbTest.SelectedIndex != -1)
            {
                //選択中のコード値をテキストボックスに表示
                txtCode.Text = cmbTest.SelectedValue.ToString();
            }
        }
    }
}

CSVの部分をSQLに書き換えても使えます。
データテーブルの作成の処理の前に、リストの中に配列が入っていればOKです。

データテーブルの作成に至る前に、リストの中に配列を入れています。二次元配列か多段階配列にする方法も考えましたが、ソースコードが非常に煩雑になるため、リストにしています。

#参考

2
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?