C# ComboBoxのSelectedItemを取得・設定する方法|null対策とSelectedValueとの違いも解説

はじめに

C#でComboBoxを扱うとき、選択されている項目を取得したり、コードから初期値を選択したりする場面はよくあります。そのときによく使うのがSelectedItemです。

ただし、ComboBox.SelectedItemは一見シンプルに見えて、実際には次のような疑問やトラブルが起きやすいプロパティです。

「SelectedItemで取得できる値は何なのか」
「SelectedItemがnullになるのはなぜか」
「SelectedValueやTextとは何が違うのか」
「DataSourceを使った場合はどう書けばよいのか」
「オブジェクトを設定しているのに選択されないのはなぜか」

この記事では、C#のComboBoxにおけるSelectedItemの取得・設定方法を、WinFormsを中心に解説します。あわせて、null対策、SelectedIndexTextSelectedValueとの違い、WPFでの扱い方、よくあるエラーの原因と解決方法まで整理します。

1. C#のComboBox.SelectedItemとは

ComboBox.SelectedItemとは、ComboBoxで現在選択されている項目そのものを取得または設定するためのプロパティです。

WinFormsのComboBoxでは、Itemsに追加した要素や、DataSourceに設定したデータのうち、現在選択されている1件がSelectedItemとして返されます。

たとえば、次のように文字列をComboBoxに追加している場合を考えます。

C#
comboBox1.Items.Add("東京");
comboBox1.Items.Add("大阪");
comboBox1.Items.Add("名古屋");

ユーザーが「大阪」を選択している場合、SelectedItemには"大阪"が入ります。

C#
object selected = comboBox1.SelectedItem;

SelectedItemの型はobjectです。そのため、文字列として扱いたい場合はstringに変換し、独自クラスとして扱いたい場合は目的の型にキャストして使用します。

1-1. SelectedItemで取得できる値

SelectedItemで取得できる値は、ComboBoxに登録されている項目そのものです。

文字列を登録している場合は、選択された文字列が取得できます。

C#
comboBox1.Items.Add("Apple");
comboBox1.Items.Add("Orange");
comboBox1.Items.Add("Grape");

string? selectedFruit = comboBox1.SelectedItem as string;

独自クラスのオブジェクトを登録している場合は、選択されたオブジェクトそのものが取得できます。

C#
public class Category
{
public int Id { get; set; }
public string Name { get; set; } = "";
}
C#
var categories = new List<Category>
{
new Category { Id = 1, Name = "食品" },
new Category { Id = 2, Name = "家電" },
new Category { Id = 3, Name = "書籍" }
};

comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

この場合、SelectedItemで取得できるのはCategoryオブジェクトです。

C#
Category? selectedCategory = comboBox1.SelectedItem as Category;

if (selectedCategory != null)
{
int id = selectedCategory.Id;
string name = selectedCategory.Name;
}

つまり、SelectedItemは画面に表示されている文字列そのものとは限りません。ComboBoxに入っているデータの実体を取得するプロパティだと考えると分かりやすいです。

1-2. SelectedIndex・Text・SelectedValueとの違い

ComboBoxには、選択状態を扱うプロパティが複数あります。特に混同しやすいのが、SelectedItemSelectedIndexTextSelectedValueです。

SelectedItemは、選択されている項目そのものを表します。

C#
object item = comboBox1.SelectedItem;

SelectedIndexは、選択されている項目のインデックス番号を表します。先頭は0です。何も選択されていない場合は-1になります。

C#
int index = comboBox1.SelectedIndex;

Textは、ComboBoxに表示されている文字列を表します。選択項目の表示文字列を取得する場合にも使えますが、ComboBoxの設定によってはユーザーが直接入力した文字列になることもあります。

C#
string text = comboBox1.Text;

SelectedValueは、ValueMemberで指定したプロパティの値を取得します。DataSourceを使っている場合に、IDなどの内部値を取得したいときに便利です。

C#
object value = comboBox1.SelectedValue;

たとえば、画面にはカテゴリ名を表示し、内部的にはカテゴリIDを取得したい場合はSelectedValueが向いています。一方、選択されたデータ全体を扱いたい場合はSelectedItemが向いています。

1-3. SelectedItemを使う主な場面

SelectedItemは、主に次のような場面で使います。

ComboBoxで選択された文字列を取得したい場合。

C#
string? selected = comboBox1.SelectedItem as string;

ComboBoxで選択されたオブジェクトを取得したい場合。

C#
Product? product = comboBox1.SelectedItem as Product;

コードから特定の項目を選択状態にしたい場合。

C#
comboBox1.SelectedItem = "大阪";

選択された項目に応じて処理を分岐したい場合。

C#
if (comboBox1.SelectedItem?.ToString() == "管理者")
{
// 管理者向けの処理
}

ComboBoxに文字列だけを入れている場合も、クラスの一覧をバインドしている場合も、SelectedItemはよく使われます。特に、選択されたオブジェクトの複数のプロパティを利用したい場合はSelectedValueよりもSelectedItemの方が扱いやすいことがあります。

2. ComboBoxのSelectedItemを取得する方法

ComboBoxで選択中の値を取得する基本は、SelectedItemを参照するだけです。

ただし、SelectedItemobject型であり、未選択時にはnullになる可能性があります。そのため、実際のコードでは型変換とnullチェックを意識することが重要です。

2-1. 選択中の項目を取得する基本コード

もっとも基本的な取得方法は次のとおりです。

C#
object selectedItem = comboBox1.SelectedItem;

ただし、このコードはSelectedItemnullの場合に注意が必要です。安全に扱うなら、次のようにnullチェックを行います。

C#
if (comboBox1.SelectedItem != null)
{
object selectedItem = comboBox1.SelectedItem;
MessageBox.Show(selectedItem.ToString());
}
else
{
MessageBox.Show("項目が選択されていません。");
}

SelectedItemは選択されている項目そのものを返します。ComboBoxに文字列を入れていれば文字列、クラスのインスタンスを入れていればそのオブジェクトが返されます。

2-2. 文字列として取得する方法

ComboBoxに文字列を追加している場合は、as stringで変換するのが分かりやすいです。

C#
string? selectedText = comboBox1.SelectedItem as string;

if (selectedText != null)
{
MessageBox.Show($"選択された項目: {selectedText}");
}

ToString()を使って文字列化する方法もあります。

C#
if (comboBox1.SelectedItem != null)
{
string selectedText = comboBox1.SelectedItem.ToString();
MessageBox.Show(selectedText);
}

null許容参照型を有効にしている場合は、ToString()の戻り値がnullになる可能性も考慮して、次のように書くとより安全です。

C#
string selectedText = comboBox1.SelectedItem?.ToString() ?? "";

ただし、ComboBoxに独自クラスを入れている場合、ToString()の結果はクラス名になることがあります。表示用の文字列が欲しい場合は、DisplayMemberや対象プロパティを使う方が適切です。

2-3. オブジェクトとして取得する方法

ComboBoxに独自クラスの一覧を設定している場合、SelectedItemはそのクラスのインスタンスとして取得できます。

C#
public class Employee
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string Department { get; set; } = "";
}
C#
var employees = new List<Employee>
{
new Employee { Id = 1, Name = "佐藤", Department = "営業部" },
new Employee { Id = 2, Name = "鈴木", Department = "開発部" },
new Employee { Id = 3, Name = "田中", Department = "総務部" }
};

comboBox1.DataSource = employees;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

選択された社員データを取得するには、次のようにキャストします。

C#
Employee? selectedEmployee = comboBox1.SelectedItem as Employee;

if (selectedEmployee != null)
{
MessageBox.Show(
$"ID: {selectedEmployee.Id}\n" +
$"名前: {selectedEmployee.Name}\n" +
$"部署: {selectedEmployee.Department}"
);
}

このように、SelectedItemを使うと選択されたオブジェクト全体にアクセスできます。IDだけでなく、名前、部署、その他のプロパティも同時に使いたい場合に便利です。

2-4. 未選択時にnullになるケース

SelectedItemは、何も選択されていない場合にnullになります。

たとえば、次のようなケースです。

フォーム表示直後に初期選択を設定していない場合。

C#
comboBox1.Items.Add("A");
comboBox1.Items.Add("B");
comboBox1.Items.Add("C");

// SelectedIndexを設定していないため、SelectedItemはnullの可能性がある

選択状態を解除した場合。

C#
comboBox1.SelectedIndex = -1;

DataSourceに空のリストを設定している場合。

C#
comboBox1.DataSource = new List<string>();

DataSourceを再設定した直後に、選択状態が変わった場合。

C#
comboBox1.DataSource = null;
comboBox1.DataSource = newList;

未選択の可能性がある場面では、必ずnullチェックを入れることが重要です。

C#
if (comboBox1.SelectedItem == null)
{
MessageBox.Show("選択してください。");
return;
}

3. ComboBoxのSelectedItemを設定する方法

SelectedItemは取得だけでなく、コードから選択項目を設定することもできます。

C#
comboBox1.SelectedItem = "大阪";

ただし、設定する値はComboBoxのItemsまたはDataSource内に存在している必要があります。存在しない値を設定しても、選択状態は変わりません。

3-1. 文字列リストからSelectedItemを設定する

文字列をComboBoxに追加している場合、同じ文字列をSelectedItemに代入すれば選択できます。

C#
comboBox1.Items.Add("東京");
comboBox1.Items.Add("大阪");
comboBox1.Items.Add("名古屋");

comboBox1.SelectedItem = "大阪";

このコードを実行すると、「大阪」が選択状態になります。

リストから設定する場合は、次のように書くこともできます。

C#
var cities = new List<string> { "東京", "大阪", "名古屋" };

comboBox1.DataSource = cities;
comboBox1.SelectedItem = "名古屋";

文字列の場合は値が一致すれば選択されるため、比較的分かりやすく動作します。ただし、前後に空白がある、全角半角が違う、大文字小文字が違うと一致しない場合があります。

C#
comboBox1.SelectedItem = "大阪 "; // 末尾に空白があるため一致しない可能性がある

3-2. オブジェクトリストからSelectedItemを設定する

独自クラスのリストをComboBoxに設定している場合、SelectedItemにはリスト内に存在するオブジェクトの参照を設定する必要があります。

C#
var products = new List<Product>
{
new Product { Id = 1, Name = "ノートPC" },
new Product { Id = 2, Name = "マウス" },
new Product { Id = 3, Name = "キーボード" }
};

comboBox1.DataSource = products;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

comboBox1.SelectedItem = products[1];

この場合、「マウス」が選択されます。

注意点は、同じ値を持つ新しいオブジェクトを作成して設定しても、選択されないことがある点です。

C#
comboBox1.SelectedItem = new Product { Id = 2, Name = "マウス" };

見た目の値は同じでも、ComboBox内のリストに存在するインスタンスとは別物です。そのため、期待どおりに選択されない場合があります。

このような場合は、リスト内から対象オブジェクトを検索して設定します。

C#
var selectedProduct = products.FirstOrDefault(p => p.Id == 2);

if (selectedProduct != null)
{
comboBox1.SelectedItem = selectedProduct;
}

IDなどの値で選択したい場合は、SelectedValueを使う方法もあります。

C#
comboBox1.SelectedValue = 2;

3-3. 初期表示時にSelectedItemを設定する

フォーム表示時に初期値を選択したい場合は、ComboBoxに項目を追加した後、またはDataSourceを設定した後にSelectedItemを設定します。

C#
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.Items.Add("未対応");
comboBox1.Items.Add("対応中");
comboBox1.Items.Add("完了");

comboBox1.SelectedItem = "対応中";
}

DataSourceを使う場合も、先にDataSourceを設定してからSelectedItemを設定します。

C#
private void Form1_Load(object sender, EventArgs e)
{
var statuses = new List<string> { "未対応", "対応中", "完了" };

comboBox1.DataSource = statuses;
comboBox1.SelectedItem = "未対応";
}

独自クラスの場合は、リスト内の対象オブジェクトを設定します。

C#
private List<Category> categories = new();

private void Form1_Load(object sender, EventArgs e)
{
categories = new List<Category>
{
new Category { Id = 1, Name = "食品" },
new Category { Id = 2, Name = "家電" },
new Category { Id = 3, Name = "書籍" }
};

comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

comboBox1.SelectedItem = categories.FirstOrDefault(c => c.Id == 2);
}

初期値をIDで指定したい場合は、SelectedValueを使うと簡潔です。

C#
comboBox1.SelectedValue = 2;

3-4. SelectedItemが反映されない原因

SelectedItemを設定しても選択されない場合、主な原因は次のとおりです。

設定した値がComboBox内に存在していない。

C#
comboBox1.Items.Add("東京");
comboBox1.SelectedItem = "福岡"; // Itemsに存在しないため選択されない

DataSourceを設定する前にSelectedItemを設定している。

C#
comboBox1.SelectedItem = "大阪";
comboBox1.DataSource = cities; // 後からDataSourceを設定すると選択状態が変わる可能性がある

オブジェクトの参照が一致していない。

C#
comboBox1.SelectedItem = new Category { Id = 2, Name = "家電" };

DisplayMemberValueMemberの指定が間違っている。

C#
comboBox1.DisplayMember = "CategoryName"; // 実際のプロパティ名と違う

DataSourceを再設定して、選択状態がリセットされている。

C#
comboBox1.DataSource = null;
comboBox1.DataSource = categories;

SelectedItemが反映されないときは、まず「設定した値がComboBoxの中に存在するか」を確認するのが基本です。文字列なら完全一致しているか、オブジェクトならリスト内の同じインスタンスを設定しているかを確認しましょう。

4. SelectedItemのnull対策

ComboBox.SelectedItemを使ううえで重要なのがnull対策です。

未選択状態ではSelectedItemnullになるため、何も確認せずにToString()やキャスト後のプロパティへアクセスすると、NullReferenceExceptionが発生する可能性があります。

4-1. nullチェックの基本

もっとも基本的なnullチェックは次の形です。

C#
if (comboBox1.SelectedItem != null)
{
string text = comboBox1.SelectedItem.ToString();
MessageBox.Show(text);
}
else
{
MessageBox.Show("項目が選択されていません。");
}

早期returnを使うと、処理が読みやすくなります。

C#
if (comboBox1.SelectedItem == null)
{
MessageBox.Show("項目を選択してください。");
return;
}

string selectedText = comboBox1.SelectedItem.ToString();
MessageBox.Show(selectedText);

独自クラスにキャストする場合は、as演算子を使うと安全です。

C#
Category? category = comboBox1.SelectedItem as Category;

if (category == null)
{
MessageBox.Show("カテゴリを選択してください。");
return;
}

MessageBox.Show($"選択カテゴリ: {category.Name}");

4-2. NullReferenceExceptionを防ぐ書き方

NullReferenceExceptionを防ぐには、null条件演算子?.やnull合体演算子??を使う方法もあります。

C#
string selectedText = comboBox1.SelectedItem?.ToString() ?? "未選択";

このコードでは、SelectedItemがnullの場合は"未選択"が代入されます。

メッセージ表示だけなら、次のように簡潔に書けます。

C#
MessageBox.Show(comboBox1.SelectedItem?.ToString() ?? "項目が選択されていません。");

ただし、業務処理や登録処理では、未選択のまま処理を進めるよりも、明示的にチェックして処理を止める方が安全です。

C#
if (comboBox1.SelectedItem is not Category category)
{
MessageBox.Show("カテゴリを選択してください。");
return;
}

SaveCategory(category.Id);

is notを使うと、nullチェックと型チェックを同時に行えます。

4-3. 未選択時のデフォルト値を用意する

未選択状態を避けたい場合は、あらかじめデフォルト値を選択しておく方法があります。

C#
comboBox1.Items.Add("選択してください");
comboBox1.Items.Add("東京");
comboBox1.Items.Add("大阪");
comboBox1.Items.Add("名古屋");

comboBox1.SelectedIndex = 0;

ただし、「選択してください」は実際の選択値ではないため、登録時には除外する必要があります。

C#
if (comboBox1.SelectedIndex == 0)
{
MessageBox.Show("都道府県を選択してください。");
return;
}

独自クラスを使う場合も、未選択用のデータを用意できます。

C#
var categories = new List<Category>
{
new Category { Id = 0, Name = "選択してください" },
new Category { Id = 1, Name = "食品" },
new Category { Id = 2, Name = "家電" }
};

comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";
comboBox1.SelectedValue = 0;

登録時には、IDが0なら未選択として扱います。

C#
if ((int)comboBox1.SelectedValue == 0)
{
MessageBox.Show("カテゴリを選択してください。");
return;
}

4-4. SelectedIndexが-1の場合の扱い

ComboBoxでは、何も選択されていない状態をSelectedIndex == -1で判定できます。

C#
if (comboBox1.SelectedIndex == -1)
{
MessageBox.Show("未選択です。");
return;
}

SelectedItem == nullSelectedIndex == -1は、どちらも未選択の判定に使えます。

C#
if (comboBox1.SelectedIndex < 0)
{
return;
}

選択を解除したい場合も、SelectedIndex-1を設定します。

C#
comboBox1.SelectedIndex = -1;

ただし、DataSourceやDropDownStyleの設定、フォーム初期化のタイミングによっては、意図せず選択が入ることがあります。未選択を明示したい場合は、DataSource設定後にSelectedIndex = -1を設定すると分かりやすいです。

C#
comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

comboBox1.SelectedIndex = -1;

5. SelectedItemとSelectedValueの違い

SelectedItemSelectedValueはどちらもComboBoxの選択値を扱うプロパティですが、意味が異なります。

簡単にいうと、SelectedItemは選択された項目そのもの、SelectedValueは選択された項目の中からValueMemberで指定した値を取り出したものです。

5-1. SelectedItemは選択された項目そのもの

SelectedItemは、ComboBox内で選択されている項目そのものを返します。

文字列リストなら文字列が返ります。

C#
comboBox1.DataSource = new List<string> { "東京", "大阪", "名古屋" };

string? city = comboBox1.SelectedItem as string;

オブジェクトリストならオブジェクトが返ります。

C#
Category? category = comboBox1.SelectedItem as Category;

選択されたデータ全体を使いたい場合は、SelectedItemが便利です。

C#
if (comboBox1.SelectedItem is Category category)
{
Console.WriteLine(category.Id);
Console.WriteLine(category.Name);
}

5-2. SelectedValueはValueMemberで指定した値

SelectedValueは、ValueMemberで指定したプロパティの値を返します。

C#
comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

この場合、画面にはNameが表示されますが、SelectedValueではIdを取得できます。

C#
int categoryId = (int)comboBox1.SelectedValue;

たとえば、カテゴリ一覧から「家電」を選択していて、そのカテゴリのIDが2なら、SelectedValue2になります。

DB登録などでIDだけが必要な場合は、SelectedValueを使うとコードが簡潔になります。

5-3. DisplayMember・ValueMemberとの関係

DisplayMemberValueMemberは、DataSourceにオブジェクトリストを設定するときによく使います。

DisplayMemberは、ComboBoxに表示するプロパティを指定します。

C#
comboBox1.DisplayMember = "Name";

ValueMemberは、SelectedValueで取得するプロパティを指定します。

C#
comboBox1.ValueMember = "Id";

たとえば、次のクラスがあるとします。

C#
public class Category
{
public int Id { get; set; }
public string Name { get; set; } = "";
}

設定例は次のとおりです。

C#
comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

この場合、それぞれの意味は次のようになります。

C#
// 選択されたCategoryオブジェクト
Category? item = comboBox1.SelectedItem as Category;

// 選択されたCategoryのId
int id = (int)comboBox1.SelectedValue;

// 画面に表示されている文字列
string text = comboBox1.Text;

SelectedItemSelectedValueTextは似ていますが、取得している対象が異なります。

5-4. どちらを使うべきかの判断基準

SelectedItemを使うべきなのは、選択されたオブジェクト全体を扱いたい場合です。

C#
if (comboBox1.SelectedItem is Category category)
{
Save(category.Id, category.Name);
}

SelectedValueを使うべきなのは、IDなど特定の値だけが必要な場合です。

C#
int categoryId = (int)comboBox1.SelectedValue;
Save(categoryId);

文字列だけのComboBoxであれば、SelectedItemまたはTextで十分なことが多いです。

C#
string? selected = comboBox1.SelectedItem as string;

一方、マスターデータのように「表示名」と「内部ID」が分かれている場合は、DisplayMemberValueMemberを設定し、ID取得にはSelectedValueを使うのが一般的です。

画面表示に使う名前、DB保存に使うID、処理に使うオブジェクト全体を分けて考えると、どのプロパティを使うべきか判断しやすくなります。

6. DataSourceを使ったComboBoxでのSelectedItem

ComboBoxには、Items.Addで1件ずつ追加する方法のほかに、DataSourceを使ってリストや配列をまとめて設定する方法があります。

DataSourceを使う場合でも、SelectedItemの基本的な考え方は同じです。選択されたデータそのものが返されます。

6-1. Listや配列をDataSourceに設定する方法

文字列のListをDataSourceに設定する例です。

C#
var fruits = new List<string>
{
"りんご",
"みかん",
"ぶどう"
};

comboBox1.DataSource = fruits;

選択された項目は、次のように取得できます。

C#
string? selectedFruit = comboBox1.SelectedItem as string;

if (selectedFruit != null)
{
MessageBox.Show(selectedFruit);
}

配列を設定することもできます。

C#
string[] colors = { "赤", "青", "緑" };

comboBox1.DataSource = colors;

DataSourceを使うと、リストの内容をComboBoxに簡単に反映できます。ただし、DataSourceを設定している場合、Items.Addで直接項目を追加しようとするとエラーになることがあります。DataSourceを使う場合は、基本的に元のリスト側を更新します。

6-2. クラスのプロパティを表示する方法

独自クラスの一覧をComboBoxに表示する場合は、DisplayMemberを使います。

C#
public class Customer
{
public int CustomerId { get; set; }
public string CustomerName { get; set; } = "";
}
C#
var customers = new List<Customer>
{
new Customer { CustomerId = 1, CustomerName = "株式会社A" },
new Customer { CustomerId = 2, CustomerName = "株式会社B" },
new Customer { CustomerId = 3, CustomerName = "株式会社C" }
};

comboBox1.DataSource = customers;
comboBox1.DisplayMember = "CustomerName";
comboBox1.ValueMember = "CustomerId";

この設定により、ComboBoxにはCustomerNameが表示されます。

DisplayMemberを設定しない場合、ComboBoxにはクラス名が表示されることがあります。その場合は、DisplayMemberを正しく指定するか、クラス側でToString()をオーバーライドします。

C#
public override string ToString()
{
return CustomerName;
}

ただし、実務ではDisplayMemberを使う方が、表示用プロパティと内部値を分けやすいため分かりやすいです。

6-3. 選択されたオブジェクトから値を取り出す方法

DataSourceにクラスの一覧を設定している場合、SelectedItemを対象の型にキャストしてプロパティを取り出します。

C#
Customer? selectedCustomer = comboBox1.SelectedItem as Customer;

if (selectedCustomer == null)
{
MessageBox.Show("顧客を選択してください。");
return;
}

int customerId = selectedCustomer.CustomerId;
string customerName = selectedCustomer.CustomerName;

MessageBox.Show($"ID: {customerId}, 顧客名: {customerName}");

C#のパターンマッチングを使うと、より簡潔に書けます。

C#
if (comboBox1.SelectedItem is Customer customer)
{
MessageBox.Show($"{customer.CustomerId}: {customer.CustomerName}");
}
else
{
MessageBox.Show("顧客が選択されていません。");
}

この書き方は、nullチェックと型チェックを同時に行えるためおすすめです。

6-4. SelectedItemとSelectedValueの実装例

SelectedItemSelectedValueを両方使う例を見てみましょう。

C#
public class Department
{
public int Id { get; set; }
public string Name { get; set; } = "";
}
C#
private void Form1_Load(object sender, EventArgs e)
{
var departments = new List<Department>
{
new Department { Id = 1, Name = "営業部" },
new Department { Id = 2, Name = "開発部" },
new Department { Id = 3, Name = "総務部" }
};

comboBox1.DataSource = departments;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";
}

選択された部署オブジェクト全体を取得する場合です。

C#
if (comboBox1.SelectedItem is Department department)
{
MessageBox.Show($"部署名: {department.Name}");
}

選択された部署IDだけを取得する場合です。

C#
if (comboBox1.SelectedValue is int departmentId)
{
MessageBox.Show($"部署ID: {departmentId}");
}

初期値をIDで設定する場合は、SelectedValueが便利です。

C#
comboBox1.SelectedValue = 2;

選択されたオブジェクト全体を使うならSelectedItem、IDだけを使うならSelectedValueと考えると整理しやすいです。

7. SelectedIndexChangedイベントでSelectedItemを扱う方法

ComboBoxの選択が変更されたタイミングで処理を実行したい場合は、SelectedIndexChangedイベントを使います。

このイベント内でSelectedItemを取得すれば、ユーザーが選択した項目に応じた処理を実装できます。

7-1. 選択変更時にSelectedItemを取得する

基本的な書き方は次のとおりです。

C#
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedItem != null)
{
MessageBox.Show(comboBox1.SelectedItem.ToString());
}
}

senderをComboBoxとして扱う場合は、次のように書けます。

C#
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox comboBox = (ComboBox)sender;

if (comboBox.SelectedItem != null)
{
MessageBox.Show(comboBox.SelectedItem.ToString());
}
}

複数のComboBoxで同じイベントハンドラーを使う場合は、senderを使うと便利です。

7-2. フォーム初期化時にイベントが発火する注意点

SelectedIndexChangedイベントは、ユーザーが選択を変更したときだけでなく、コードでSelectedIndexSelectedItemを設定したときにも発火します。

たとえば、フォーム初期化時にDataSourceを設定しただけでイベントが実行されることがあります。

C#
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";
}

このとき、まだ他のコントロールの初期化が終わっていない状態でイベント処理が動き、予期しないエラーになることがあります。

対策として、初期化中フラグを用意します。

C#
private bool _isInitializing = false;

private void Form1_Load(object sender, EventArgs e)
{
_isInitializing = true;

comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

_isInitializing = false;
}

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (_isInitializing)
{
return;
}

// 通常の選択変更処理
}

初期化時のイベント発火を避けたい場合は、イベントを一時的に解除する方法もあります。

C#
comboBox1.SelectedIndexChanged -= comboBox1_SelectedIndexChanged;

comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

comboBox1.SelectedIndexChanged += comboBox1_SelectedIndexChanged;

7-3. nullチェックを含めた安全なイベント処理

イベント内では、SelectedItemがnullになる可能性を考慮して書きます。

C#
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedItem is not Category category)
{
return;
}

label1.Text = $"選択中: {category.Name}";
}

SelectedIndexで未選択を判定してもよいです。

C#
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex < 0)
{
label1.Text = "未選択";
return;
}

label1.Text = comboBox1.SelectedItem?.ToString() ?? "";
}

DataSourceを再設定すると、イベントが複数回発火することもあります。そのため、イベント内では常にnullや型の確認を行う習慣をつけると安全です。

7-4. 選択内容に応じて処理を分岐する例

文字列の選択内容に応じて処理を分岐する例です。

C#
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string selected = comboBox1.SelectedItem?.ToString() ?? "";

switch (selected)
{
case "管理者":
label1.Text = "管理者メニューを表示します。";
break;

case "一般ユーザー":
label1.Text = "一般ユーザー向けメニューを表示します。";
break;

case "ゲスト":
label1.Text = "ゲスト向けメニューを表示します。";
break;

default:
label1.Text = "権限を選択してください。";
break;
}
}

独自クラスの場合は、IDや区分で分岐できます。

C#
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedItem is not Role role)
{
return;
}

switch (role.Id)
{
case 1:
ShowAdminMenu();
break;

case 2:
ShowUserMenu();
break;

default:
ShowDefaultMenu();
break;
}
}

文字列で分岐するより、IDやEnumのような安定した値で分岐した方が、表示名の変更に強いコードになります。

8. WinFormsとWPFでのSelectedItemの違い

C#でComboBoxを使う代表的なUIフレームワークには、WinFormsとWPFがあります。どちらにもSelectedItemはありますが、使い方や設計思想に違いがあります。

WinFormsではコードビハインドで直接ComboBoxを操作することが多く、WPFではデータバインディングを使ってViewModelのプロパティと連携することが多いです。

8-1. WinFormsのComboBox.SelectedItem

WinFormsのComboBoxでは、comboBox1.SelectedItemのようにコントロールを直接参照して選択項目を取得します。

C#
private void button1_Click(object sender, EventArgs e)
{
string selected = comboBox1.SelectedItem?.ToString() ?? "未選択";
MessageBox.Show(selected);
}

DataSourceを使う場合も、コントロールに直接設定します。

C#
comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

選択されたオブジェクトを取得する場合は、キャストして使います。

C#
if (comboBox1.SelectedItem is Category category)
{
MessageBox.Show(category.Name);
}

WinFormsでは、イベントハンドラー内でSelectedItemを取得して処理する書き方が一般的です。

8-2. WPFのComboBox.SelectedItem

WPFのComboBoxでも、SelectedItemを使って選択項目を扱えます。

XML
<ComboBox x:Name="comboBox1"
DisplayMemberPath="Name"
SelectedValuePath="Id" />

コードビハインドでItemsSourceを設定する例です。

C#
comboBox1.ItemsSource = categories;
comboBox1.DisplayMemberPath = "Name";
comboBox1.SelectedValuePath = "Id";

選択された項目を取得する場合は、WinFormsと同様にSelectedItemを使います。

C#
if (comboBox1.SelectedItem is Category category)
{
MessageBox.Show(category.Name);
}

WPFでは、WinFormsのDataSourceではなくItemsSourceを使います。また、DisplayMemberではなくDisplayMemberPathValueMemberではなくSelectedValuePathを使います。

8-3. バインディング時のSelectedItemの使い方

WPFでは、SelectedItemをViewModelのプロパティにバインドすることがよくあります。

XML
<ComboBox ItemsSource="{Binding Categories}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedCategory, Mode=TwoWay}" />

ViewModel側の例です。

C#
public class MainViewModel
{
public List<Category> Categories { get; set; } = new();

public Category? SelectedCategory { get; set; }
}

このようにすると、ComboBoxで選択された項目がSelectedCategoryに自動的に反映されます。

SelectedValueを使う場合は、次のように書きます。

XML
<ComboBox ItemsSource="{Binding Categories}"
DisplayMemberPath="Name"
SelectedValuePath="Id"
SelectedValue="{Binding SelectedCategoryId, Mode=TwoWay}" />

ViewModel側ではIDを持ちます。

C#
public int SelectedCategoryId { get; set; }

オブジェクト全体を扱いたいならSelectedItem、IDだけを扱いたいならSelectedValueをバインドします。

8-4. MVVMでSelectedItemを扱う場合の考え方

WPFのMVVMでは、ViewのComboBoxをコードビハインドから直接操作するのではなく、ViewModelのプロパティを通じて選択状態を管理します。

C#
private Category? _selectedCategory;

public Category? SelectedCategory
{
get => _selectedCategory;
set
{
_selectedCategory = value;
OnPropertyChanged(nameof(SelectedCategory));
}
}

XAMLでは次のようにバインドします。

XML
<ComboBox ItemsSource="{Binding Categories}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedCategory, Mode=TwoWay}" />

この設計にすると、選択されたカテゴリをViewModel側で自然に扱えます。

C#
public void Save()
{
if (SelectedCategory == null)
{
return;
}

int categoryId = SelectedCategory.Id;
}

MVVMでは、ComboBoxそのものではなく、選択状態を表すプロパティを中心に考えます。これにより、画面とロジックの結合を弱くでき、テストや保守がしやすくなります。

9. よくあるエラーと解決方法

ComboBox.SelectedItemを使っていると、null、型変換、DataSource、SelectedValueまわりでエラーや想定外の動作が発生しやすいです。

ここでは、よくある原因と解決方法を整理します。

9-1. SelectedItemがnullになる

SelectedItemがnullになる主な原因は、何も選択されていないことです。

C#
comboBox1.SelectedIndex = -1;

フォーム表示直後、DataSourceが空、選択解除後などはSelectedItemがnullになります。

対策は、使用前にnullチェックを行うことです。

C#
if (comboBox1.SelectedItem == null)
{
MessageBox.Show("項目を選択してください。");
return;
}

初期値を設定しておく方法もあります。

C#
comboBox1.SelectedIndex = 0;

ただし、項目が空の場合にSelectedIndex = 0を設定するとエラーになるため、件数を確認します。

C#
if (comboBox1.Items.Count > 0)
{
comboBox1.SelectedIndex = 0;
}

9-2. SelectedItemを設定しても選択されない

SelectedItemを設定しても選択されない場合は、設定した値がComboBox内に存在しているか確認します。

C#
comboBox1.SelectedItem = "大阪";

この場合、ItemsまたはDataSource内に"大阪"が存在しなければ選択されません。

オブジェクトの場合は、同じ内容でも別インスタンスだと一致しないことがあります。

C#
comboBox1.SelectedItem = new Category { Id = 2, Name = "家電" };

このような場合は、DataSourceに使っているリストから対象を探して設定します。

C#
var item = categories.FirstOrDefault(c => c.Id == 2);

if (item != null)
{
comboBox1.SelectedItem = item;
}

IDで選択したいだけなら、SelectedValueを使う方が簡単です。

C#
comboBox1.SelectedValue = 2;

9-3. オブジェクト比較で一致しない

独自クラスをComboBoxに設定している場合、SelectedItemに新しいオブジェクトを代入しても選択されないことがあります。

C#
var item = new Category { Id = 1, Name = "食品" };
comboBox1.SelectedItem = item;

ComboBox内に同じインスタンスが存在しない場合、選択対象として認識されません。

解決方法は、元のリストから取得したインスタンスを設定することです。

C#
comboBox1.SelectedItem = categories.FirstOrDefault(x => x.Id == 1);

または、クラスでEqualsGetHashCodeを適切にオーバーライドする方法もあります。

C#
public override bool Equals(object? obj)
{
return obj is Category category && category.Id == Id;
}

public override int GetHashCode()
{
return Id.GetHashCode();
}

ただし、ComboBoxの選択設定のためだけに比較ロジックを変更すると、他の処理に影響する可能性があります。多くの場合は、リスト内のインスタンスを検索して設定する方法が分かりやすく安全です。

9-4. SelectedValueが期待した値にならない

SelectedValueが期待した値にならない場合は、ValueMemberの指定を確認します。

C#
comboBox1.ValueMember = "Id";

プロパティ名が間違っていると、正しく値を取得できません。

C#
comboBox1.ValueMember = "CategoryId"; // 実際に存在しない場合は問題になる

また、DataSourceDisplayMemberValueMemberの設定順にも注意します。基本的には、次のようにまとめて設定します。

C#
comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

SelectedValueを取得する前に、未選択でないかも確認します。

C#
if (comboBox1.SelectedValue is int id)
{
MessageBox.Show(id.ToString());
}

DataSource設定直後や初期化中にSelectedValueChangedイベントが発火し、想定外の値になることもあります。その場合は初期化中フラグを使います。

9-5. DataSource設定後に選択状態が変わる

DataSourceを設定すると、ComboBoxの選択状態が自動的に先頭項目になることがあります。

C#
comboBox1.DataSource = categories;

未選択状態にしたい場合は、DataSource設定後にSelectedIndex = -1を設定します。

C#
comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

comboBox1.SelectedIndex = -1;

初期値を設定したい場合も、DataSource設定後に行います。

C#
comboBox1.SelectedValue = 2;

DataSourceを再設定すると、選択状態がリセットされることがあります。再読み込み処理では、以前の選択値を保存しておき、再設定後に復元するとよいです。

C#
int? selectedId = comboBox1.SelectedValue as int?;

comboBox1.DataSource = null;
comboBox1.DataSource = newCategories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

if (selectedId != null)
{
comboBox1.SelectedValue = selectedId.Value;
}

10. ComboBox.SelectedItemの実践サンプル

ここでは、実際に使いやすいSelectedItemのサンプルを紹介します。文字列リスト、クラスの一覧、初期値設定、null対策を含めた例を確認しましょう。

10-1. 文字列リストの選択値を取得するサンプル

C#
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.Items.Add("東京");
comboBox1.Items.Add("大阪");
comboBox1.Items.Add("名古屋");
}

private void button1_Click(object sender, EventArgs e)
{
if (comboBox1.SelectedItem == null)
{
MessageBox.Show("都市を選択してください。");
return;
}

string city = comboBox1.SelectedItem.ToString() ?? "";
MessageBox.Show($"選択された都市: {city}");
}

この例では、ユーザーが選択した都市名をSelectedItemから取得しています。

より簡潔に書くなら、次のようにもできます。

C#
private void button1_Click(object sender, EventArgs e)
{
string city = comboBox1.SelectedItem?.ToString() ?? "未選択";
MessageBox.Show(city);
}

入力必須の項目であれば、前者のように未選択時に処理を止める方が適しています。

10-2. クラスの一覧から選択されたデータを取得するサンプル

C#
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
C#
private void Form1_Load(object sender, EventArgs e)
{
var products = new List<Product>
{
new Product { Id = 1, Name = "ノートPC", Price = 120000 },
new Product { Id = 2, Name = "マウス", Price = 3000 },
new Product { Id = 3, Name = "キーボード", Price = 8000 }
};

comboBox1.DataSource = products;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";
}
C#
private void button1_Click(object sender, EventArgs e)
{
if (comboBox1.SelectedItem is not Product product)
{
MessageBox.Show("商品を選択してください。");
return;
}

MessageBox.Show(
$"商品ID: {product.Id}\n" +
$"商品名: {product.Name}\n" +
$"価格: {product.Price:N0}円"
);
}

このサンプルでは、ComboBoxには商品名だけを表示し、選択された商品オブジェクトからIDや価格を取り出しています。

10-3. SelectedItemで初期値を設定するサンプル

文字列リストで初期値を設定する例です。

C#
private void Form1_Load(object sender, EventArgs e)
{
var statuses = new List<string>
{
"未対応",
"対応中",
"完了"
};

comboBox1.DataSource = statuses;
comboBox1.SelectedItem = "対応中";
}

独自クラスで初期値を設定する例です。

C#
public class StatusItem
{
public int Id { get; set; }
public string Name { get; set; } = "";
}
C#
private List<StatusItem> statuses = new();

private void Form1_Load(object sender, EventArgs e)
{
statuses = new List<StatusItem>
{
new StatusItem { Id = 1, Name = "未対応" },
new StatusItem { Id = 2, Name = "対応中" },
new StatusItem { Id = 3, Name = "完了" }
};

comboBox1.DataSource = statuses;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

comboBox1.SelectedItem = statuses.FirstOrDefault(x => x.Id == 2);
}

IDで初期選択するなら、次のようにSelectedValueを使うこともできます。

C#
comboBox1.SelectedValue = 2;

10-4. null対策を含めた安全なサンプル

最後に、null対策を含めた実践的な例です。

C#
public class UserRole
{
public int Id { get; set; }
public string Name { get; set; } = "";
}
C#
private void Form1_Load(object sender, EventArgs e)
{
var roles = new List<UserRole>
{
new UserRole { Id = 0, Name = "選択してください" },
new UserRole { Id = 1, Name = "管理者" },
new UserRole { Id = 2, Name = "一般ユーザー" },
new UserRole { Id = 3, Name = "ゲスト" }
};

comboBox1.DataSource = roles;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";
comboBox1.SelectedValue = 0;
}
C#
private void button1_Click(object sender, EventArgs e)
{
if (comboBox1.SelectedItem is not UserRole role)
{
MessageBox.Show("権限を選択してください。");
return;
}

if (role.Id == 0)
{
MessageBox.Show("有効な権限を選択してください。");
return;
}

MessageBox.Show($"選択された権限: {role.Name}");
}

この例では、未選択用の項目を用意し、IDが0の場合は登録処理を進めないようにしています。業務アプリでは、このように「未選択」と「有効な選択値」を明確に分けると安全です。

11. C# ComboBoxのSelectedItemに関するよくある質問

11-1. SelectedItemとTextは何が違う?

SelectedItemは、ComboBoxで選択されている項目そのものです。一方、TextはComboBoxに表示されている文字列です。

文字列リストだけを扱う場合は似た結果になることがあります。

C#
string item = comboBox1.SelectedItem?.ToString() ?? "";
string text = comboBox1.Text;

ただし、独自クラスをDataSourceに設定している場合、SelectedItemはオブジェクト、Textは表示文字列になります。

また、ComboBoxの入力が許可されている場合、Textにはユーザーが直接入力した文字列が入ることがあります。必ずリスト内の選択項目を取得したい場合はSelectedItemを使う方が適しています。

11-2. SelectedItemをstringに変換してもよい?

ComboBoxに文字列だけを入れている場合は、SelectedItemをstringに変換して問題ありません。

C#
string? selected = comboBox1.SelectedItem as string;

または、表示文字列として使うだけならToString()でもよいです。

C#
string selected = comboBox1.SelectedItem?.ToString() ?? "";

ただし、独自クラスを入れている場合、ToString()の結果が期待した表示名になるとは限りません。オブジェクトとしてキャストし、必要なプロパティを取り出す方が安全です。

C#
if (comboBox1.SelectedItem is Category category)
{
string name = category.Name;
}

11-3. SelectedItemがobject型になるのはなぜ?

ComboBoxには、文字列だけでなく任意のオブジェクトを項目として入れられます。

C#
comboBox1.Items.Add("文字列");
comboBox1.Items.Add(new Category { Id = 1, Name = "食品" });

このように、ComboBoxはさまざまな型の項目を扱えるため、SelectedItemは特定の型ではなくobject型として定義されています。

そのため、実際に使うときは目的の型に変換します。

C#
string? text = comboBox1.SelectedItem as string;
C#
Category? category = comboBox1.SelectedItem as Category;

型が分かっている場合でも、nullや型違いの可能性を考慮して安全にキャストすることが大切です。

11-4. SelectedValueを使ったほうがよいケースは?

SelectedValueを使った方がよいのは、選択された項目のIDなど、特定の値だけが必要な場合です。

たとえば、カテゴリ名を画面に表示し、DBにはカテゴリIDを保存する場合です。

C#
comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";
C#
int categoryId = (int)comboBox1.SelectedValue;

このようなケースでは、SelectedItemからオブジェクトを取得してIDを取り出すより、SelectedValueを使う方が簡潔です。

一方で、選択された項目の複数のプロパティを使いたい場合は、SelectedItemの方が便利です。

C#
if (comboBox1.SelectedItem is Category category)
{
int id = category.Id;
string name = category.Name;
}

11-5. 未選択状態に戻すにはどうすればよい?

ComboBoxを未選択状態に戻すには、SelectedIndex-1を設定します。

C#
comboBox1.SelectedIndex = -1;

これにより、SelectedItemはnullになります。

C#
if (comboBox1.SelectedItem == null)
{
MessageBox.Show("未選択です。");
}

ただし、DataSource設定直後や初期値設定後に未選択へ戻したい場合は、DataSourceを設定した後にSelectedIndex = -1を実行します。

C#
comboBox1.DataSource = categories;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";

comboBox1.SelectedIndex = -1;

未選択状態を許可したくない場合は、先頭項目を選択しておきます。

C#
if (comboBox1.Items.Count > 0)
{
comboBox1.SelectedIndex = 0;
}

入力必須のComboBoxでは、未選択を許可するのか、デフォルト値を選択するのかを仕様として決めておくことが重要です。

まとめ

C#のComboBox.SelectedItemは、ComboBoxで現在選択されている項目そのものを取得・設定するためのプロパティです。

文字列をComboBoxに入れている場合は、SelectedItemから選択された文字列を取得できます。独自クラスの一覧をDataSourceに設定している場合は、選択されたオブジェクトそのものを取得できます。

C#
string? text = comboBox1.SelectedItem as string;
C#
if (comboBox1.SelectedItem is Category category)
{
int id = category.Id;
string name = category.Name;
}

未選択時にはSelectedItemがnullになるため、使用前のnullチェックは必須です。

C#
if (comboBox1.SelectedItem == null)
{
MessageBox.Show("項目を選択してください。");
return;
}

また、SelectedItemSelectedValueは役割が異なります。SelectedItemは選択された項目そのもの、SelectedValueValueMemberで指定した値です。

選択されたオブジェクト全体を使いたい場合はSelectedItem、IDなどの内部値だけを使いたい場合はSelectedValueを使うとよいでしょう。

DataSourceを使う場合は、DisplayMemberValueMemberSelectedItemSelectedValueの関係を理解しておくことが大切です。特に、オブジェクトをSelectedItemに設定する場合は、DataSource内に存在する同じインスタンスを指定する必要があります。

ComboBoxの選択処理では、null対策、型変換、初期化時のイベント発火、DataSource再設定時の選択リセットに注意することで、安定したコードを書けます。