C#のコンボボックス完全ガイド|値の追加・取得・選択イベント・初期表示まで初心者向けに解説
はじめに
C#でデスクトップアプリケーションを開発する際、複数の選択肢から1つを選んでもらうためによく使われるのがコンボボックス(ComboBox)です。
コンボボックスは、都道府県、商品カテゴリ、ユーザー区分、並び順などの選択に適しています。しかし、実際に使おうとすると、次のような疑問が生じやすいでしょう。
コンボボックスに項目を追加するにはどうすればよいのか
選択中の文字列やIDを取得するにはどうすればよいのか
初期値として特定の項目を表示するにはどうすればよいのか
選択が変更されたときに処理を実行するにはどうすればよいのか
SelectedItem、SelectedValue、Textはどのように使い分けるのか
本記事では、Windows Formsを中心に、C#のコンボボックスの基本から、項目の追加・削除、選択値の取得、初期表示、選択変更イベント、データバインドまで詳しく解説します。後半ではWPFのComboBoxについても取り上げます。
1. C#のコンボボックス(ComboBox)とは
1-1. コンボボックスの基本的な役割
コンボボックスは、複数の候補をドロップダウン形式で表示し、その中から1つの項目を選択するためのコントロールです。
たとえば、次のような画面で利用できます。
都道府県の選択
商品カテゴリの選択
ユーザー権限の選択
表示件数の選択
並び順の選択
年月や曜日の選択
通常時は選択中の項目だけが表示されるため、複数の選択肢を省スペースで配置できます。
Windows Formsでは、System.Windows.Forms.ComboBoxクラスを使用します。
ComboBox comboBox = new ComboBox();WPFでは、System.Windows.Controls.ComboBoxクラスを使用します。
1-2. リストボックスやテキストボックスとの違い
コンボボックスと似たコントロールには、リストボックスやテキストボックスがあります。
リストボックスは、複数の項目を常に一覧表示するコントロールです。選択肢を一目で確認しやすい一方、項目数が多いと画面上のスペースを大きく使用します。
テキストボックスは、ユーザーが任意の文字列を入力するためのコントロールです。入力の自由度は高いものの、表記揺れや入力ミスが発生する可能性があります。
コンボボックスは、決められた候補から選択させながら、必要に応じて文字入力も許可できます。選択肢を省スペースで表示したい場合に適しています。
| コントロール | 主な用途 | 特徴 |
|---|---|---|
| ComboBox | 候補から1つ選択 | ドロップダウン形式で省スペース |
| ListBox | 候補を一覧表示して選択 | 複数項目を常に表示できる |
| TextBox | 任意の文字列を入力 | 自由入力に適している |
1-3. Windows FormsとWPFのComboBoxの違い
Windows FormsとWPFには、どちらにもComboBoxがあります。ただし、使用する名前空間や画面の作成方法、データバインドの仕組みが異なります。
Windows Formsでは、Visual Studioのフォームデザイナーを使用してコントロールを配置する方法が一般的です。項目はItemsやDataSourceを使って設定します。
WPFでは、XAMLを使って画面を定義します。項目の設定にはItemsSource、表示項目の指定にはDisplayMemberPath、選択値の指定にはSelectedValuePathを使用します。
| 項目 | Windows Forms | WPF |
| 名前空間 | System.Windows.Forms | System.Windows.Controls |
| 画面定義 | デザイナーまたはC# | XAMLまたはC# |
| データ設定 | Items、DataSource | Items、ItemsSource |
| 表示項目 | DisplayMember | DisplayMemberPath |
| 内部値 | ValueMember | SelectedValuePath |
| 選択イベント | SelectedIndexChangedなど | SelectionChanged |
本記事の第2章から第8章まではWindows Formsを中心に解説し、第9章でWPFのComboBoxを解説します。
1-4. 本記事で使用するサンプル画面と前提環境
Windows Formsのサンプルでは、次の環境を想定します。
Visual Studio
C#
Windows Formsアプリケーション
フォーム名:
Form1コンボボックス名:
comboBox1結果表示用ラベル名:
label1
コード例は、主にフォームのコンストラクター、Loadイベント、ボタンのクリックイベント、コンボボックスの選択変更イベントに記述します。
フォームのコンストラクターで初期化する場合は、必ずInitializeComponentの後に処理を記述します。
public Form1(){InitializeComponent();comboBox1.Items.Add("東京都");
}
InitializeComponentより前にcomboBox1へアクセスすると、コントロールがまだ生成されていないため、正しく処理できません。
2. C#でコンボボックスをフォームに配置する方法
2-1. Visual Studioのデザイナーから配置する
Windows Formsでは、Visual Studioのデザイナーを使って簡単にコンボボックスを配置できます。
フォームをデザイナーで開き、ツールボックスから「ComboBox」を選択してフォーム上へドラッグします。
配置後は、プロパティウィンドウから次のような設定を変更できます。
(Name):コードから参照するときの名前DropDownStyle:入力方式Items:表示する項目Sorted:自動的に並べ替えるかEnabled:操作可能にするかVisible:画面に表示するか
デザイナーから配置した場合、コントロールの生成やフォームへの追加処理は、Form1.Designer.csに自動生成されます。
通常は、自動生成されたコードを直接編集せず、プロパティウィンドウまたはフォーム側のコードで設定します。
2-2. コードからComboBoxを生成して配置する
コンボボックスは、デザイナーを使用せず、C#コードから生成することもできます。
public Form1(){InitializeComponent();ComboBox categoryComboBox = new ComboBox();categoryComboBox.Name = "categoryComboBox";categoryComboBox.Left = 20;categoryComboBox.Top = 20;categoryComboBox.Width = 200;categoryComboBox.Items.AddRange(new object[]{"書籍","家電","食品"});Controls.Add(categoryComboBox);
}
new ComboBox()でインスタンスを生成し、位置やサイズを設定した後、フォームのControlsコレクションへ追加します。
動的に入力欄を作成する画面や、設定内容に応じてコントロール数が変わる画面では、コードからの生成が便利です。
2-3. NameやDropDownStyleなどの基本プロパティを設定する
コンボボックスでよく使用する基本プロパティは次のとおりです。
comboBox1.Name = "comboBoxPrefecture";comboBox1.Width = 200;comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;comboBox1.Sorted = false;comboBox1.MaxDropDownItems = 10;Nameはコード上でコントロールを識別するための名前です。デザイナーで設定する場合は、プロパティウィンドウの(Name)を変更します。
DropDownStyleは、文字入力を許可するかどうかを設定する重要なプロパティです。
指定できる主な値は次の3つです。
| 値 | 動作 |
ComboBoxStyle.DropDown | 候補選択と文字入力の両方が可能 |
ComboBoxStyle.DropDownList | 候補からの選択のみ可能 |
ComboBoxStyle.Simple | 入力欄と一覧を常に表示 |
一般的な選択専用のコンボボックスでは、DropDownListを使用します。
2-4. ユーザーによる文字入力を禁止する
ユーザーによる文字入力を禁止し、登録済みの項目だけを選択させるには、DropDownStyleへDropDownListを設定します。
comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;デザイナーを使用する場合は、プロパティウィンドウから次のように設定できます。
DropDownStyle = DropDownListDropDownListにすると、ユーザーは自由な文字列を入力できません。都道府県や商品カテゴリなど、選択肢を限定したい場合に適しています。
なお、DropDownListでは、項目に存在しない文字列をTextへ設定しても、その文字列を自由入力のように表示することはできません。初期表示を設定したい場合は、SelectedIndex、SelectedItem、SelectedValueなどを使用します。
3. コンボボックスに項目を追加・削除する方法
3-1. Items.Addで項目を1件追加する
コンボボックスへ項目を1件追加するには、Items.Addを使用します。
comboBox1.Items.Add("東京都");comboBox1.Items.Add("神奈川県");comboBox1.Items.Add("千葉県");Items.Addの戻り値は、追加された項目のインデックスです。
int index = comboBox1.Items.Add("埼玉県");MessageBox.Show($"追加位置は{index}です。");
インデックスは0から始まります。最初に追加した項目のインデックスは0、2番目の項目は1です。
3-2. Items.AddRangeで複数の項目を一括追加する
複数の項目をまとめて追加するには、Items.AddRangeを使用します。
comboBox1.Items.AddRange(new object[]{"東京都","神奈川県","千葉県","埼玉県"});1件ずつItems.Addを呼び出すよりも、複数の固定項目を簡潔に記述できます。
文字列配列を用意して追加することも可能です。
string[] prefectures ={"東京都","神奈川県","千葉県","埼玉県"};comboBox1.Items.AddRange(prefectures);
3-3. Listや配列から項目を追加する
List<string>の内容をコンボボックスへ追加する場合は、foreachを使用できます。
List<string> categories = new List<string>{"書籍","家電","食品"};foreach (string category in categories){comboBox1.Items.Add(category);}
List<T>を配列に変換し、AddRangeで追加することもできます。
List<string> categories = new List<string>{"書籍","家電","食品"};comboBox1.Items.AddRange(categories.ToArray());
ただし、一覧データをオブジェクトとして管理する場合は、項目をコピーするよりも、後述するDataSourceによるデータバインドが便利です。
comboBox1.DataSource = categories;DataSourceを設定した場合、通常はItems.AddやItems.AddRangeで項目を追加しません。リスト側を更新して、データソースを再設定するか、BindingList<T>などを使用します。
3-4. Items.Insertで指定位置に項目を挿入する
指定した位置に項目を挿入するには、Items.Insertを使用します。
comboBox1.Items.Add("東京都");comboBox1.Items.Add("千葉県");comboBox1.Items.Insert(1, "神奈川県");
実行後の項目は次の順番になります。
0: 東京都1: 神奈川県2: 千葉県先頭へ項目を追加したい場合は、インデックスに0を指定します。
comboBox1.Items.Insert(0, "選択してください");存在しない位置を指定すると例外が発生するため、インデックスの範囲に注意しましょう。
3-5. Items.Remove・RemoveAtで項目を削除する
指定した項目を削除するには、Items.Removeを使用します。
comboBox1.Items.Remove("東京都");Removeは、指定した内容と一致する項目を検索して削除します。対象が存在しない場合でも、通常は例外になりません。
インデックスを指定して削除する場合は、Items.RemoveAtを使用します。
if (comboBox1.Items.Count > 0){comboBox1.Items.RemoveAt(0);}選択中の項目を削除する例は次のとおりです。
if (comboBox1.SelectedIndex >= 0){comboBox1.Items.RemoveAt(comboBox1.SelectedIndex);}未選択状態ではSelectedIndexが-1になるため、削除前に確認する必要があります。
3-6. Items.Clearですべての項目を削除する
コンボボックス内の項目をすべて削除するには、Items.Clearを使用します。
comboBox1.Items.Clear();一覧を再読み込みするときは、重複を防ぐため、追加前にClearを実行します。
private void LoadCategories(){comboBox1.Items.Clear();comboBox1.Items.Add("書籍");comboBox1.Items.Add("家電");comboBox1.Items.Add("食品");
}
ただし、DataSourceが設定されている場合は、Items.Clearで直接削除するのではなく、データソースを解除または更新します。
comboBox1.DataSource = null;comboBox1.Items.Clear();3-7. 項目数をItems.Countで取得する
コンボボックスに登録されている項目数は、Items.Countで取得できます。
int count = comboBox1.Items.Count;MessageBox.Show($"項目数は{count}件です。");
項目が1件以上ある場合だけ先頭を選択する処理は、次のように記述できます。
if (comboBox1.Items.Count > 0){comboBox1.SelectedIndex = 0;}Items.Countは、項目の追加、削除、初期選択などを安全に処理するためによく使用します。
4. コンボボックスの選択値を取得する方法
4-1. SelectedItemで選択中の項目を取得する
選択中の項目そのものを取得するには、SelectedItemを使用します。
if (comboBox1.SelectedItem != null){string selectedText = comboBox1.SelectedItem.ToString();MessageBox.Show(selectedText);}文字列だけを登録している場合、SelectedItemには選択された文字列が格納されます。
comboBox1.Items.Add("東京都");comboBox1.Items.Add("神奈川県");一方、独自クラスのオブジェクトを登録している場合、SelectedItemにはそのオブジェクトが格納されます。
Category? selectedCategory = comboBox1.SelectedItem as Category;if (selectedCategory != null){int id = selectedCategory.Id;string name = selectedCategory.Name;}
4-2. SelectedIndexで選択位置を取得する
選択中の項目の位置を取得するには、SelectedIndexを使用します。
int selectedIndex = comboBox1.SelectedIndex;先頭項目は0、2番目は1です。何も選択されていない場合は-1になります。
if (comboBox1.SelectedIndex == -1){MessageBox.Show("項目が選択されていません。");}else{MessageBox.Show($"選択位置は{comboBox1.SelectedIndex}です。");}選択位置によって処理を分岐することもできますが、項目の並び順が変更される可能性がある場合は、インデックスではなくIDや値を使用するほうが安全です。
4-3. SelectedValueで選択項目の値を取得する
表示文字列とは別の内部値を取得するには、SelectedValueを使用します。
SelectedValueは、主にDataSourceとValueMemberを設定したコンボボックスで利用します。
comboBox1.DataSource = categories;comboBox1.DisplayMember = "Name";comboBox1.ValueMember = "Id";選択されたカテゴリのIDは、次のように取得できます。
if (comboBox1.SelectedValue != null){int categoryId = Convert.ToInt32(comboBox1.SelectedValue);MessageBox.Show($"カテゴリIDは{categoryId}です。");}SelectedValueの型はobjectです。そのため、必要な型へ変換して使用します。
データバインドしていない状態では、期待する値をSelectedValueから取得できないことがあります。単純に文字列をItems.Addで追加した場合は、SelectedItemまたはTextを使用します。
4-4. Textプロパティで表示文字列を取得する
コンボボックスに現在表示されている文字列は、Textで取得できます。
string text = comboBox1.Text;選択項目が文字列の場合は、SelectedItem.ToString()と同じような結果になります。
MessageBox.Show($"選択内容:{comboBox1.Text}");DropDownStyleがDropDownの場合、ユーザーが候補に存在しない文字列を入力できるため、Textには自由入力された文字列が格納されることがあります。
そのため、登録済み項目の選択を前提とする処理では、SelectedIndexやSelectedItemも確認しましょう。
if (comboBox1.SelectedIndex >= 0){string selectedText = comboBox1.Text;}else{string inputText = comboBox1.Text;}4-5. 未選択時のnullやSelectedIndex「-1」を判定する
コンボボックスが未選択の場合、SelectedItemやSelectedValueがnullになり、SelectedIndexは-1になります。
安全に選択値を取得するには、事前に未選択状態を確認します。
if (comboBox1.SelectedIndex < 0){MessageBox.Show("項目を選択してください。");return;}string selectedText = comboBox1.Text;
SelectedItemを確認する方法もあります。
if (comboBox1.SelectedItem == null){MessageBox.Show("項目が選択されていません。");return;}string selectedText = comboBox1.SelectedItem.ToString() ?? string.Empty;
データバインドしている場合は、SelectedValueも確認します。
if (comboBox1.SelectedValue == null){MessageBox.Show("値を取得できません。");return;}4-6. SelectedItem・SelectedValue・Textの違いと使い分け
SelectedItem、SelectedValue、Textは似ていますが、取得する内容が異なります。
| プロパティ | 取得内容 | 主な用途 |
SelectedItem | 選択された項目オブジェクト | 選択したオブジェクト全体を取得 |
SelectedValue | ValueMemberで指定した値 | IDやコードを取得 |
Text | 画面に表示されている文字列 | 表示名や入力文字列を取得 |
SelectedIndex | 選択位置 | 未選択判定や位置取得 |
文字列だけをItemsへ追加している場合は、SelectedItemまたはTextを使用します。
string selectedText = comboBox1.Text;オブジェクトをデータバインドし、IDを取得したい場合は、SelectedValueを使用します。
int selectedId = Convert.ToInt32(comboBox1.SelectedValue);選択したオブジェクトの複数のプロパティを利用したい場合は、SelectedItemを元の型へ変換します。
Category? category = comboBox1.SelectedItem as Category;if (category != null){int id = category.Id;string name = category.Name;}
5. コンボボックスの初期値・初期表示を設定する方法
5-1. SelectedIndexで先頭項目を初期選択する
コンボボックスの先頭項目を初期選択するには、SelectedIndexへ0を設定します。
comboBox1.Items.AddRange(new object[]{"東京都","神奈川県","千葉県"});comboBox1.SelectedIndex = 0;
項目が存在しない状態で0を設定すると正しく選択できないため、Items.Countを確認すると安全です。
if (comboBox1.Items.Count > 0){comboBox1.SelectedIndex = 0;}5-2. SelectedItemで特定の項目を初期選択する
登録されている項目と一致する内容を指定するには、SelectedItemを使用します。
comboBox1.Items.AddRange(new object[]{"東京都","神奈川県","千葉県"});comboBox1.SelectedItem = "神奈川県";
指定した項目が存在しない場合は選択されません。
独自オブジェクトを登録している場合は、コンボボックス内に存在する同じインスタンスを指定する必要がある点に注意してください。
Category book = new Category{Id = 1,Name = "書籍"};Category appliance = new Category{Id = 2,Name = "家電"};
comboBox1.Items.Add(book);comboBox1.Items.Add(appliance);
comboBox1.SelectedItem = appliance;
別途生成した、内容だけが同じオブジェクトを指定しても、期待どおりに選択されないことがあります。IDで選択する場合は、データバインドとSelectedValueを使用すると扱いやすくなります。
5-3. SelectedValueで値を指定して初期選択する
DataSource、DisplayMember、ValueMemberを設定している場合は、SelectedValueで内部値を指定できます。
List<Category> categories = new List<Category>{new Category { Id = 1, Name = "書籍" },new Category { Id = 2, Name = "家電" },new Category { Id = 3, Name = "食品" }};comboBox1.DataSource = categories;comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);
comboBox1.SelectedValue = 2;
この例では、IDが2の「家電」が選択されます。
型が一致しないと選択されないことがあります。Idがint型である場合は、文字列の"2"ではなく、整数の2を指定します。
5-4. Textで初期表示する文字列を設定する
DropDownStyleがDropDownの場合は、Textへ文字列を設定できます。
comboBox1.DropDownStyle = ComboBoxStyle.DropDown;comboBox1.Text = "カテゴリを入力または選択";登録済みの項目と同じ文字列を指定すると、その内容が表示されます。
comboBox1.Text = "書籍";ただし、選択肢のみを許可するDropDownListでは、存在しない文字列を自由な初期表示として設定する用途には向きません。
DropDownListで案内文を表示したい場合は、「選択してください」という項目をリストに追加します。
5-5. 「選択してください」を先頭に表示する
コンボボックスの先頭に案内用の項目を追加する方法は、次のとおりです。
comboBox1.Items.Add("選択してください");comboBox1.Items.Add("書籍");comboBox1.Items.Add("家電");comboBox1.Items.Add("食品");comboBox1.SelectedIndex = 0;
登録処理では、案内項目が選ばれていないか確認します。
if (comboBox1.SelectedIndex <= 0){MessageBox.Show("カテゴリを選択してください。");return;}データバインドを使用する場合は、案内用データをリストの先頭へ追加します。
List<Category> categories = new List<Category>{new Category { Id = 0, Name = "選択してください" },new Category { Id = 1, Name = "書籍" },new Category { Id = 2, Name = "家電" },new Category { Id = 3, Name = "食品" }};comboBox1.DataSource = categories;comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.SelectedValue = 0;
登録処理では、IDが0なら未選択として扱います。
if (Convert.ToInt32(comboBox1.SelectedValue) == 0){MessageBox.Show("カテゴリを選択してください。");return;}実際のデータでIDが0を使用する可能性がある場合は、案内項目に使用する値を設計に合わせて決めましょう。
5-6. 初期状態を未選択にする
初期状態で何も選択しない場合は、SelectedIndexへ-1を設定します。
comboBox1.SelectedIndex = -1;項目追加後やデータバインド後に設定します。
comboBox1.Items.AddRange(new object[]{"書籍","家電","食品"});comboBox1.SelectedIndex = -1;
未選択状態では、SelectedItemはnull、SelectedIndexは-1になります。
if (comboBox1.SelectedIndex == -1){MessageBox.Show("カテゴリを選択してください。");}5-7. フォーム表示時に初期値を設定する際の注意点
初期値は、項目を追加した後、またはデータバインドした後に設定します。
次の順番が基本です。
private void Form1_Load(object sender, EventArgs e){comboBox1.DataSource = GetCategories();comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.SelectedValue = 2;
}
初期値を先に設定してからDataSourceを設定すると、データバインドによって選択状態が上書きされる可能性があります。
// 推奨しない順番comboBox1.SelectedValue = 2;comboBox1.DataSource = GetCategories();また、データバインド中にSelectedIndexChangedが発生することがあります。初期化中に不要な処理を実行したくない場合は、初期化フラグを使用します。
private bool isInitializing;private void Form1_Load(object sender, EventArgs e){isInitializing = true;
comboBox1.DataSource = GetCategories();comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.SelectedValue = 2;isInitializing = false;
}
6. コンボボックスの選択変更イベントを処理する方法
6-1. SelectedIndexChangedイベントの基本的な書き方
選択項目が変更されたときに処理を実行するには、SelectedIndexChangedイベントを使用します。
private void comboBox1_SelectedIndexChanged(object sender,EventArgs e){if (comboBox1.SelectedIndex < 0){return;}label1.Text = $"選択内容:{comboBox1.Text}";
}
デザイナーでは、コンボボックスを選択し、プロパティウィンドウのイベント一覧からSelectedIndexChangedをダブルクリックすると、イベントハンドラーを作成できます。
コードから登録することも可能です。
public Form1(){InitializeComponent();comboBox1.SelectedIndexChanged+= comboBox1_SelectedIndexChanged;
}
6-2. SelectionChangeCommittedとの違い
Windows FormsのComboBoxには、SelectedIndexChangedのほかにSelectionChangeCommittedがあります。
SelectedIndexChangedは、ユーザー操作だけでなく、コードから選択値を変更した場合や、データバインドによって選択状態が変化した場合にも発生します。
comboBox1.SelectedIndex = 1;一方、SelectionChangeCommittedは、基本的にユーザーがドロップダウンから項目を選択し、変更を確定したときに発生します。
private void comboBox1_SelectionChangeCommitted(object sender,EventArgs e){label1.Text = $"ユーザーが選択:{comboBox1.Text}";}| イベント | ユーザー操作 | コードによる変更 | データバインド時 |
SelectedIndexChanged | 発生する | 発生する | 発生することがある |
SelectionChangeCommitted | 発生する | 通常は発生しない | 通常は発生しない |
6-3. ユーザー操作による変更だけを検知する
ユーザーが操作した場合だけ処理したいときは、SelectionChangeCommittedを使用します。
private void comboBox1_SelectionChangeCommitted(object sender,EventArgs e){if (comboBox1.SelectedIndex < 0){return;}MessageBox.Show($"「{comboBox1.Text}」が選択されました。");
}
たとえば、選択時にデータベース検索やAPI通信などの比較的重い処理を実行する場合、初期化によるイベント発生を避けるために役立ちます。
ただし、キーボード操作を含むユーザーによる選択変更も考慮し、実際の画面操作で期待どおりに発生するか確認しましょう。
6-4. 選択した値に応じて画面表示を切り替える
選択内容に応じて、ラベルの表示や入力欄の有効状態を切り替えられます。
private void comboBox1_SelectedIndexChanged(object sender,EventArgs e){switch (comboBox1.Text){case "個人":label1.Text = "氏名を入力してください。";textBox1.Enabled = true;break; case "法人":label1.Text = "法人名を入力してください。";textBox1.Enabled = true;break;default:label1.Text = "区分を選択してください。";textBox1.Enabled = false;break;}
}
データバインドしている場合は、表示文字列ではなくIDで分岐すると、名称変更の影響を受けにくくなります。
private void comboBox1_SelectedIndexChanged(object sender,EventArgs e){if (comboBox1.SelectedValue == null){return;}if (comboBox1.SelectedValue is Category category){return;}if (!int.TryParse(comboBox1.SelectedValue.ToString(),out int categoryId)){return;}detailsPanel.Visible = categoryId == 2;
}
バインド処理の途中では、SelectedValueに想定外のオブジェクトが入る場合があります。そのため、単純なキャストだけでなく、null判定や型確認を行うと安全です。
6-5. 初期化中にイベントが発生するのを防ぐ
SelectedIndexChangedは、項目の追加、DataSourceの設定、初期値の設定などでも発生することがあります。
初期化中の処理を除外するには、フラグを使用します。
private bool isInitializing;private void Form1_Load(object sender, EventArgs e){isInitializing = true;
comboBox1.DataSource = GetCategories();comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.SelectedIndex = 0;isInitializing = false;
}
private void comboBox1_SelectedIndexChanged(object sender,EventArgs e){if (isInitializing){return;}
label1.Text = comboBox1.Text;
}
tryとfinallyを使用すると、途中で例外が発生した場合でもフラグを戻せます。
private void InitializeComboBox(){isInitializing = true;try{comboBox1.DataSource = GetCategories();comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.SelectedIndex = 0;}finally{isInitializing = false;}
}
一時的にイベントを解除する方法もあります。
comboBox1.SelectedIndexChanged-= comboBox1_SelectedIndexChanged;comboBox1.DataSource = GetCategories();comboBox1.SelectedIndex = 0;
comboBox1.SelectedIndexChanged+= comboBox1_SelectedIndexChanged;
イベントの再登録を忘れる可能性があるため、一般的には初期化フラグのほうが管理しやすいでしょう。
6-6. イベント内で未選択状態を安全に処理する
項目の再読み込みや選択解除によって、イベント内で未選択状態になることがあります。
イベントの先頭でSelectedIndexを確認します。
private void comboBox1_SelectedIndexChanged(object sender,EventArgs e){if (comboBox1.SelectedIndex == -1){label1.Text = "未選択";return;}label1.Text = comboBox1.Text;
}
オブジェクトを取得する場合は、型パターンを利用できます。
private void comboBox1_SelectedIndexChanged(object sender,EventArgs e){if (comboBox1.SelectedItem is not Category category){label1.Text = "カテゴリが選択されていません。";return;}label1.Text = $"ID:{category.Id} 名前:{category.Name}";
}
このように記述すると、nullと型の不一致を同時に判定できます。
7. オブジェクトやデータベースの値をコンボボックスに表示する方法
7-1. DataSourceを使ってデータをバインドする
オブジェクトのリストやデータベースから取得した一覧を表示する場合は、DataSourceを使用します。
まず、カテゴリを表すクラスを作成します。
public class Category{public int Id { get; set; }public string Name { get; set; } = string.Empty;
}
次に、リストをコンボボックスへ設定します。
List<Category> categories = new List<Category>{new Category { Id = 1, Name = "書籍" },new Category { Id = 2, Name = "家電" },new Category { Id = 3, Name = "食品" }};comboBox1.DataSource = categories;
DataSourceだけを設定した場合、クラスのToStringの結果が表示されます。通常は、DisplayMemberとValueMemberも設定します。
7-2. DisplayMemberで表示項目を指定する
コンボボックスに表示するプロパティは、DisplayMemberで指定します。
comboBox1.DataSource = categories;comboBox1.DisplayMember = nameof(Category.Name);これにより、各CategoryオブジェクトのNameが画面に表示されます。
文字列で直接指定することもできます。
comboBox1.DisplayMember = "Name";ただし、nameofを使用すると、プロパティ名を変更したときにコンパイル時に問題を発見しやすくなります。
comboBox1.DisplayMember = nameof(Category.Name);7-3. ValueMemberで内部値を指定する
選択項目の内部値として使用するプロパティは、ValueMemberで指定します。
comboBox1.ValueMember = nameof(Category.Id);DisplayMemberと組み合わせた例は次のとおりです。
comboBox1.DataSource = categories;comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);画面には「書籍」「家電」「食品」が表示されますが、SelectedValueからは1、2、3のIDを取得できます。
7-4. SelectedValueからIDを取得する
選択中のIDは、SelectedValueから取得します。
if (comboBox1.SelectedValue != null){int categoryId =Convert.ToInt32(comboBox1.SelectedValue);MessageBox.Show($"選択ID:{categoryId}");
}
変換に失敗する可能性を考慮する場合は、int.TryParseを使用します。
if (int.TryParse(comboBox1.SelectedValue?.ToString(),out int categoryId)){MessageBox.Show($"選択ID:{categoryId}");}選択中のオブジェクト全体が必要な場合は、SelectedItemを使用します。
if (comboBox1.SelectedItem is Category category){MessageBox.Show($"ID:{category.Id}\n名前:{category.Name}");}7-5. Listオブジェクトをバインドするサンプル
List<Category>をバインドする一連のサンプルは次のとおりです。
public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender,EventArgs e){List<Category> categories = new List<Category>{new Category { Id = 1, Name = "書籍" },new Category { Id = 2, Name = "家電" },new Category { Id = 3, Name = "食品" }};comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = categories;comboBox1.SelectedIndex = -1;}private void button1_Click(object sender,EventArgs e){if (comboBox1.SelectedItem is not Category category){MessageBox.Show("カテゴリを選択してください。");return;}MessageBox.Show($"ID:{category.Id}\n名前:{category.Name}");}
}
DisplayMemberとValueMemberを先に設定してからDataSourceを設定しておくと、バインド時の表示やイベント処理を把握しやすくなります。
7-6. DataTableをバインドするサンプル
データベースの検索結果をDataTableへ格納している場合も、コンボボックスへバインドできます。
DataTable table = new DataTable();table.Columns.Add("CategoryId", typeof(int));table.Columns.Add("CategoryName", typeof(string));
table.Rows.Add(1, "書籍");table.Rows.Add(2, "家電");table.Rows.Add(3, "食品");
comboBox1.DisplayMember = "CategoryName";comboBox1.ValueMember = "CategoryId";comboBox1.DataSource = table;
選択されたIDは、SelectedValueから取得します。
if (comboBox1.SelectedValue != null){int categoryId =Convert.ToInt32(comboBox1.SelectedValue);}選択された行の内容を取得する場合、SelectedItemはDataRowViewとして取得できます。
if (comboBox1.SelectedItem is DataRowView row){int id = Convert.ToInt32(row["CategoryId"]);string name =row["CategoryName"]?.ToString() ?? string.Empty;}実際にデータベースへ接続する場合は、SQLパラメーターを使用し、接続やコマンドを適切に破棄してください。
7-7. データバインド後に初期値を設定する
初期選択は、データバインドが完了した後に設定します。
comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = categories;comboBox1.SelectedValue = 2;
未選択にする場合は、SelectedIndexへ-1を設定します。
comboBox1.SelectedIndex = -1;指定した値が存在するか確認してから設定することもできます。
int initialCategoryId = 2;bool exists = categories.Any(category => category.Id == initialCategoryId);
comboBox1.SelectedValue =exists ? initialCategoryId : null;
ただし、SelectedValueへnullを設定したときの挙動は、データソースやバインド状態によって異なる場合があります。確実に未選択にするには、SelectedIndex = -1を使用します。
8. コンボボックスの表示や操作性をカスタマイズする方法
8-1. DropDownStyleで入力方式を変更する
DropDownStyleを変更すると、ユーザーの入力方法を切り替えられます。
選択肢からのみ選ばせる場合は、DropDownListを使用します。
comboBox1.DropDownStyle =ComboBoxStyle.DropDownList;候補選択と自由入力の両方を許可する場合は、DropDownを使用します。
comboBox1.DropDownStyle =ComboBoxStyle.DropDown;入力欄とリストを常に表示する場合は、Simpleを使用します。
comboBox1.DropDownStyle =ComboBoxStyle.Simple;入力ミスを防ぎたい場合は、基本的にDropDownListが適しています。
8-2. Sortedで項目を並べ替える
Sortedをtrueにすると、追加された項目を自動的に並べ替えられます。
comboBox1.Sorted = true;comboBox1.Items.Add("みかん");comboBox1.Items.Add("りんご");comboBox1.Items.Add("バナナ");
ただし、次のような項目では、自動並べ替えが適さない場合があります。
「選択してください」を先頭に固定したい
曜日を月曜日から日曜日の順で表示したい
業務上決められた順番で表示したい
ID順や登録順を維持したい
DataSourceを使用している場合は、コンボボックス側で並べ替えるのではなく、元のリストやデータベースの検索結果を並べ替えてから設定します。
List<Category> sortedCategories = categories.OrderBy(category => category.Name).ToList();comboBox1.DataSource = sortedCategories;
8-3. MaxDropDownItemsで表示件数を調整する
ドロップダウンを開いたときに表示する最大項目数は、MaxDropDownItemsで設定します。
comboBox1.MaxDropDownItems = 8;項目数が設定値を超える場合は、スクロールして選択できます。
ただし、実際のドロップダウンの高さは、OSの表示設定やIntegralHeightなどの影響を受ける場合があります。
comboBox1.IntegralHeight = true;comboBox1.MaxDropDownItems = 10;選択肢が非常に多い場合は、オートコンプリートを有効にするか、検索画面を別途用意することも検討しましょう。
8-4. AutoCompleteModeで入力候補を表示する
入力した文字に応じて候補を表示するには、オートコンプリート機能を設定します。
comboBox1.DropDownStyle = ComboBoxStyle.DropDown;comboBox1.AutoCompleteMode =AutoCompleteMode.SuggestAppend;comboBox1.AutoCompleteSource =AutoCompleteSource.ListItems;AutoCompleteModeには、主に次の値があります。
| 値 | 動作 |
Suggest | 候補一覧を表示 |
Append | 候補文字列を入力欄へ補完 |
SuggestAppend | 候補表示と文字列補完を行う |
None | オートコンプリートを使用しない |
コンボボックス内の項目を候補にする場合は、AutoCompleteSource.ListItemsを指定します。
comboBox1.AutoCompleteSource =AutoCompleteSource.ListItems;DropDownListは自由入力欄を持たないため、文字入力による補完を使いたい場合は、通常DropDownを選択します。
8-5. Enabled・Visibleで操作可否や表示状態を切り替える
コンボボックスを操作できない状態にするには、Enabledをfalseにします。
comboBox1.Enabled = false;再び操作可能にする場合は、trueへ戻します。
comboBox1.Enabled = true;画面上から非表示にする場合は、Visibleをfalseにします。
comboBox1.Visible = false;チェックボックスの状態に応じて切り替える例は次のとおりです。
private void checkBox1_CheckedChanged(object sender,EventArgs e){comboBox1.Enabled = checkBox1.Checked;}Enabled = falseでは、表示されたまま操作できない状態になります。Visible = falseでは、コントロール自体が画面に表示されません。
8-6. 項目ごとに表示内容を変更する
Windows Formsで項目ごとに文字色や背景、表示内容を変更するには、オーナードローを使用します。
まず、DrawModeを設定します。
comboBox1.DrawMode = DrawMode.OwnerDrawFixed;comboBox1.DrawItem += comboBox1_DrawItem;次に、DrawItemイベントで描画します。
private void comboBox1_DrawItem(object? sender,DrawItemEventArgs e){if (e.Index < 0){return;}e.DrawBackground();string text =comboBox1.Items<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[e.Index]</span>?.ToString()?? string.Empty;using Brush brush = new SolidBrush(e.ForeColor);e.Graphics.DrawString(text,e.Font,brush,e.Bounds);e.DrawFocusRectangle();
}
独自オブジェクトの複数の値を組み合わせて表示することもできます。
private void comboBox1_DrawItem(object? sender,DrawItemEventArgs e){if (e.Index < 0){return;}e.DrawBackground();if (comboBox1.Items<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[e.Index]</span> is Category category){string text = $"{category.Id} - {category.Name}";TextRenderer.DrawText(e.Graphics,text,e.Font,e.Bounds,e.ForeColor,TextFormatFlags.VerticalCenter);}e.DrawFocusRectangle();
}
単に表示文字列を変更したいだけなら、クラスのToStringをオーバーライドする方法もあります。
public class Category{public int Id { get; set; }public string Name { get; set; } = string.Empty;public override string ToString(){return $"{Id} - {Name}";}
}
ただし、表示と内部値を明確に分けたい場合は、DisplayMemberとValueMemberを使用する方法が基本です。
9. WPFのComboBoxで項目追加・値取得・イベント処理を行う方法
9-1. XAMLでComboBoxItemを追加する
WPFでは、XAMLにComboBoxItemを記述して項目を追加できます。
<ComboBoxx:Name="CategoryComboBox"Width="200"SelectedIndex="0"><ComboBoxItem Content="選択してください" /><ComboBoxItem Content="書籍" /><ComboBoxItem Content="家電" /><ComboBoxItem Content="食品" /></ComboBox>コードビハインドから選択項目を取得する場合は、ComboBoxItemとして扱います。
if (CategoryComboBox.SelectedItemis ComboBoxItem selectedItem){string text =selectedItem.Content?.ToString()?? string.Empty;}単純な固定項目であればXAMLへの直接記述でも問題ありませんが、項目数が多い場合や動的に変化する場合は、ItemsSourceを使用します。
9-2. ItemsSourceでリストをバインドする
WPFでリストをバインドするには、ItemsSourceを使用します。
public partial class MainWindow : Window{public MainWindow(){InitializeComponent(); CategoryComboBox.ItemsSource =new List<Category>{new Category { Id = 1, Name = "書籍" },new Category { Id = 2, Name = "家電" },new Category { Id = 3, Name = "食品" }};}
}
XAMLでは、表示プロパティをDisplayMemberPathで指定できます。
<ComboBoxx:Name="CategoryComboBox"Width="200"DisplayMemberPath="Name" />固定のList<T>ではなく、画面表示後に項目を追加・削除する場合は、ObservableCollection<T>を使用すると変更が画面へ反映されやすくなります。
public ObservableCollection<Category> Categories{ get; } = new();public MainWindow(){InitializeComponent();
Categories.Add(new Category { Id = 1, Name = "書籍" });Categories.Add(new Category { Id = 2, Name = "家電" });CategoryComboBox.ItemsSource = Categories;
}
9-3. SelectedItem・SelectedValueを取得する
選択したオブジェクト全体を取得する場合は、SelectedItemを使用します。
if (CategoryComboBox.SelectedItemis Category category){MessageBox.Show($"ID:{category.Id}\n名前:{category.Name}");}SelectedValuePathを設定している場合は、SelectedValueからIDを取得できます。
if (CategoryComboBox.SelectedValue is int categoryId){MessageBox.Show($"ID:{categoryId}");}未選択状態では、SelectedItemやSelectedValueがnullになります。
if (CategoryComboBox.SelectedItem == null){MessageBox.Show("カテゴリを選択してください。");}9-4. DisplayMemberPathとSelectedValuePathを設定する
WPFでは、表示するプロパティをDisplayMemberPath、内部値として使用するプロパティをSelectedValuePathで指定します。
<ComboBoxx:Name="CategoryComboBox"Width="200"DisplayMemberPath="Name"SelectedValuePath="Id" />C#側でリストを設定します。
CategoryComboBox.ItemsSource =new List<Category>{new Category { Id = 1, Name = "書籍" },new Category { Id = 2, Name = "家電" },new Category { Id = 3, Name = "食品" }};IDが2の項目を初期選択する場合は、SelectedValueへ2を設定します。
CategoryComboBox.SelectedValue = 2;Windows FormsのDisplayMemberとValueMemberに近い役割ですが、WPFではプロパティ名が異なります。
9-5. SelectionChangedイベントを処理する
WPFで選択変更を検知するには、SelectionChangedイベントを使用します。
XAMLでイベントハンドラーを指定します。
<ComboBoxx:Name="CategoryComboBox"Width="200"DisplayMemberPath="Name"SelectedValuePath="Id"SelectionChanged="CategoryComboBox_SelectionChanged" />コードビハインドに処理を記述します。
private void CategoryComboBox_SelectionChanged(object sender,SelectionChangedEventArgs e){if (CategoryComboBox.SelectedItemis not Category category){ResultTextBlock.Text = "未選択";return;}ResultTextBlock.Text =$"ID:{category.Id} 名前:{category.Name}";
}
WPFのSelectionChangedも、初期値の設定やデータバインドによって発生することがあります。初期化中の処理を除外する場合は、フラグを使用するか、MVVMで選択値の変更を管理します。
9-6. MVVMで選択値をバインドする
MVVMでは、ComboBoxの選択肢と選択中の項目をViewModelへバインドします。
ViewModelの例は次のとおりです。
public class MainViewModel :INotifyPropertyChanged{private Category? selectedCategory;public ObservableCollection<Category> Categories{ get; } = new();public Category? SelectedCategory{get => selectedCategory;set{if (ReferenceEquals(selectedCategory,value)){return;}selectedCategory = value;OnPropertyChanged();}}public MainViewModel(){Categories.Add(new Category { Id = 1, Name = "書籍" });Categories.Add(new Category { Id = 2, Name = "家電" });Categories.Add(new Category { Id = 3, Name = "食品" });SelectedCategory = Categories.FirstOrDefault();}public event PropertyChangedEventHandler?PropertyChanged;protected virtual void OnPropertyChanged(<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[CallerMemberName]</span> string? propertyName = null){PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));}
}
XAMLでは、ItemsSourceとSelectedItemをバインドします。
<ComboBoxWidth="200"ItemsSource="{Binding Categories}"DisplayMemberPath="Name"SelectedItem="{Binding SelectedCategory,Mode=TwoWay}" />ウィンドウのDataContextへViewModelを設定します。
public MainWindow(){InitializeComponent();DataContext = new MainViewModel();
}
IDだけをViewModelへバインドしたい場合は、SelectedValuePathとSelectedValueを使用します。
<ComboBoxWidth="200"ItemsSource="{Binding Categories}"DisplayMemberPath="Name"SelectedValuePath="Id"SelectedValue="{Binding SelectedCategoryId,Mode=TwoWay}" />MVVMでは、画面の状態をコードビハインドへ直接記述せず、ViewModelのプロパティとして管理できる点がメリットです。
10. C#のコンボボックスでよくあるエラーと対処法
10-1. SelectedItemがnullになる
SelectedItemがnullになる主な原因は、項目が選択されていないことです。
comboBox1.SelectedIndex = -1;また、項目追加前、データバインド中、一覧の再読み込み中にもnullになる可能性があります。
取得前に必ず確認します。
if (comboBox1.SelectedItem == null){MessageBox.Show("項目を選択してください。");return;}型を指定して取得する場合は、パターンマッチングを使用すると安全です。
if (comboBox1.SelectedItem is not Category category){return;}10-2. SelectedValueが取得できない
SelectedValueが取得できない場合は、次の点を確認します。
DataSourceが設定されているかValueMemberが設定されているかValueMemberのプロパティ名が正しいか項目が選択されているか
データバインドが完了しているか
正しい設定例は次のとおりです。
comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = categories;Items.Addで文字列を追加しただけの場合は、通常SelectedItemまたはTextを使用します。
comboBox1.Items.Add("書籍");string selectedText = comboBox1.Text;
イベント内では、バインド途中の一時的な値にも注意します。
if (!int.TryParse(comboBox1.SelectedValue?.ToString(),out int categoryId)){return;}10-3. 初期値が正しく表示されない
初期値が表示されない場合は、初期値を設定する順番を確認します。
正しい基本順序は次のとおりです。
comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = categories;comboBox1.SelectedValue = 2;SelectedValueで指定する値の型も一致させます。
// Idがint型の場合comboBox1.SelectedValue = 2;次のように文字列を指定すると、一致しない場合があります。
comboBox1.SelectedValue = "2";また、指定した値がデータソースに存在しない場合は選択されません。
bool exists = categories.Any(category => category.Id == 2);10-4. SelectedIndexChangedが勝手に発生する
SelectedIndexChangedは、ユーザー操作以外でも発生します。
たとえば、次の処理で発生する可能性があります。
Items.AddやItems.ClearDataSourceの設定SelectedIndexの変更SelectedItemの変更SelectedValueの変更データソースの更新
ユーザー操作だけを検知する場合は、SelectionChangeCommittedを使用します。
private void comboBox1_SelectionChangeCommitted(object sender,EventArgs e){// ユーザーが選択したときの処理}初期化中だけ処理を除外する場合は、フラグを使用します。
if (isInitializing){return;}10-5. DataSource設定後にItemsを追加できない
DataSourceを設定すると、Itemsコレクションを直接変更できません。
次のような処理は避けます。
comboBox1.DataSource = categories;comboBox1.Items.Add("追加項目");項目を追加する場合は、元のデータソースを更新します。
categories.Add(new Category { Id = 4, Name = "衣類" });comboBox1.DataSource = null;comboBox1.DataSource = categories;comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);
頻繁に項目を追加・削除する場合は、BindingList<T>とBindingSourceを使用すると管理しやすくなります。
BindingList<Category> categories =new BindingList<Category>{new Category { Id = 1, Name = "書籍" },new Category { Id = 2, Name = "家電" }};BindingSource source = new BindingSource{DataSource = categories};
comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = source;
categories.Add(new Category { Id = 3, Name = "食品" });
10-6. 同じ項目が重複して追加される
一覧の読み込み処理を複数回実行すると、同じ項目が重複して追加されることがあります。
追加前にItems.Clearを実行します。
private void LoadItems(){comboBox1.Items.Clear();comboBox1.Items.Add("書籍");comboBox1.Items.Add("家電");comboBox1.Items.Add("食品");
}
追加前に存在確認を行う方法もあります。
string newItem = "書籍";if (!comboBox1.Items.Contains(newItem)){comboBox1.Items.Add(newItem);}
リスト側で重複を除去する場合は、Distinctを使用できます。
List<string> uniqueCategories = categories.Distinct().ToList();オブジェクトの場合は、IDなどの一意な値を基準に重複を除去します。
List<Category> uniqueCategories = categories.GroupBy(category => category.Id).Select(group => group.First()).ToList();10-7. オブジェクト名がそのまま表示される
独自クラスをそのままコンボボックスへ追加すると、次のようなクラス名が表示されることがあります。
SampleApp.Categoryこれは、表示に使用するプロパティが指定されておらず、既定のToStringが呼び出されているためです。
DisplayMemberを設定します。
comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = categories;Items.Addでオブジェクトを追加する場合は、クラスのToStringをオーバーライドする方法もあります。
public override string ToString(){return Name;}データバインドを使用する場合は、DisplayMemberを設定する方法が分かりやすいでしょう。
10-8. コンボボックスを再読み込みしても表示が更新されない
通常のList<T>をDataSourceへ設定した後、リストへ項目を追加しても、表示が自動更新されないことがあります。
categories.Add(new Category { Id = 4, Name = "衣類" });単純な方法は、DataSourceを再設定することです。
comboBox1.DataSource = null;comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = categories;選択値を維持したい場合は、再設定前に保存します。
object? selectedValue = comboBox1.SelectedValue;comboBox1.DataSource = null;comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = categories;
comboBox1.SelectedValue = selectedValue;
頻繁に更新する場合は、BindingList<T>とBindingSourceを使用します。
private readonly BindingList<Category> categories =new();private readonly BindingSource categorySource =new();
private void InitializeCategories(){categorySource.DataSource = categories;
comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = categorySource;
}
private void AddCategory(){categories.Add(new Category { Id = 4, Name = "衣類" });}
11. C#のコンボボックスに関するよくある質問
11-1. 選択中の文字列を取得するには?
画面に表示されている文字列を取得する場合は、Textを使用します。
string selectedText = comboBox1.Text;未選択を確認する場合は、SelectedIndexも判定します。
if (comboBox1.SelectedIndex < 0){MessageBox.Show("項目を選択してください。");return;}string selectedText = comboBox1.Text;
選択した項目そのものを文字列として取得する場合は、SelectedItemを使用できます。
string selectedText =comboBox1.SelectedItem?.ToString()?? string.Empty;11-2. 選択項目のIDだけを取得するには?
DisplayMemberとValueMemberを設定し、SelectedValueからIDを取得します。
comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = categories;取得処理は次のとおりです。
if (int.TryParse(comboBox1.SelectedValue?.ToString(),out int categoryId)){MessageBox.Show($"ID:{categoryId}");}11-3. 特定の値をコードから選択するには?
インデックスで選択する場合は、SelectedIndexを使用します。
comboBox1.SelectedIndex = 1;文字列項目を選択する場合は、SelectedItemを使用します。
comboBox1.SelectedItem = "家電";データバインドしている場合は、SelectedValueでIDを指定します。
comboBox1.SelectedValue = 2;文字列から項目位置を検索して選択する場合は、FindStringExactも利用できます。
int index = comboBox1.FindStringExact("家電");if (index >= 0){comboBox1.SelectedIndex = index;}
11-4. 項目を選択できない状態にするには?
コンボボックス全体を操作できない状態にするには、Enabledをfalseにします。
comboBox1.Enabled = false;再び操作できるようにするには、trueへ戻します。
comboBox1.Enabled = true;表示は維持しながら変更だけを防ぎたい場合にも、Enabledを使用できます。ただし、無効状態では表示色も変化します。
11-5. 選択を解除して空欄に戻すには?
SelectedIndexへ-1を設定します。
comboBox1.SelectedIndex = -1;DropDownStyleがDropDownの場合、入力文字も消したいときはTextを空文字列にします。
comboBox1.SelectedIndex = -1;comboBox1.Text = string.Empty;データバインドしている場合も、基本的にはSelectedIndex = -1で未選択にできます。
11-6. 項目の重複を防ぐには?
文字列項目の場合は、Items.Containsで存在確認を行います。
string item = "書籍";if (!comboBox1.Items.Contains(item)){comboBox1.Items.Add(item);}
複数の文字列を追加する場合は、Distinctで重複を除去できます。
foreach (string item in items.Distinct()){comboBox1.Items.Add(item);}独自オブジェクトの場合は、IDを基準に確認します。
Category newCategory =new Category { Id = 3, Name = "食品" };if (!categories.Any(category => category.Id == newCategory.Id)){categories.Add(newCategory);}
11-7. 選択肢を動的に更新するには?
Itemsを直接使用している場合は、既存項目を削除してから再追加します。
private void ReloadComboBox(IEnumerable<string> items){object? selectedItem = comboBox1.SelectedItem;comboBox1.BeginUpdate();try{comboBox1.Items.Clear();comboBox1.Items.AddRange(items.Cast<object>().ToArray());if (selectedItem != null&& comboBox1.Items.Contains(selectedItem)){comboBox1.SelectedItem = selectedItem;}else{comboBox1.SelectedIndex = -1;}}finally{comboBox1.EndUpdate();}
}
BeginUpdateとEndUpdateを使用すると、大量の項目を更新するときの不要な再描画を抑えられます。
データバインドしている場合は、BindingList<T>とBindingSourceを利用すると更新を反映しやすくなります。
BindingList<Category> categories =new BindingList<Category>();BindingSource source = new BindingSource{DataSource = categories};
comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = source;
categories.Add(new Category { Id = 1, Name = "書籍" });
categories.Add(new Category { Id = 2, Name = "家電" });
データベースから再取得する場合は、現在の選択IDを保存し、一覧を再設定した後に同じIDを選択すると、ユーザーの選択状態を維持できます。
object? selectedId = comboBox1.SelectedValue;List<Category> latestCategories =GetCategoriesFromDatabase();
comboBox1.DataSource = null;comboBox1.DisplayMember = nameof(Category.Name);comboBox1.ValueMember = nameof(Category.Id);comboBox1.DataSource = latestCategories;
bool exists = selectedId != null&& latestCategories.Any(category =>category.Id.ToString()== selectedId.ToString());
comboBox1.SelectedValue =exists ? selectedId : null;
if (!exists){comboBox1.SelectedIndex = -1;}
まとめ
C#のコンボボックスは、複数の候補から1つを選択してもらうための基本的なコントロールです。
Windows Formsで項目を追加する場合は、Items.Add、Items.AddRange、Items.Insertを使用します。項目を削除する場合は、Items.Remove、Items.RemoveAt、Items.Clearを使用します。
選択内容の取得方法は、目的に応じて使い分けます。
表示文字列を取得する:
Text選択項目そのものを取得する:
SelectedItemIDやコードを取得する:
SelectedValue選択位置を取得する:
SelectedIndex
初期値を設定するときは、項目追加またはデータバインドの後に、SelectedIndex、SelectedItem、SelectedValueを設定します。未選択にする場合は、SelectedIndex = -1を使用します。
選択変更を検知するには、SelectedIndexChangedまたはSelectionChangeCommittedを使用します。コードによる変更を含めて検知する場合はSelectedIndexChanged、ユーザー操作だけを検知したい場合はSelectionChangeCommittedが適しています。
データベースやオブジェクトの一覧を表示する場合は、DataSource、DisplayMember、ValueMemberを設定すると、表示名と内部IDを分けて管理できます。
WPFでは、ItemsSource、DisplayMemberPath、SelectedValuePathを使用します。MVVMで開発する場合は、選択肢をItemsSourceへ、選択中の項目をSelectedItemまたはSelectedValueへバインドするのが基本です。
コンボボックスはシンプルなコントロールですが、未選択状態、初期化時のイベント発生、データバインド後の更新などに注意が必要です。目的に合ったプロパティとイベントを選び、安全なnull判定を加えることで、扱いやすく安定した画面を実装できます。

