C# ListBoxの使い方完全ガイド|項目の追加・削除・選択値の取得・データバインドをサンプルコードで解説

はじめに

C#でデスクトップアプリケーションを開発する際、複数の候補を一覧表示し、ユーザーに項目を選択してもらうために使われる代表的なコントロールがListBoxです。

ListBoxを使うと、文字列や数値、独自クラスのオブジェクトなどを一覧表示できます。項目の追加や削除だけでなく、選択された値の取得、複数選択、データバインドにも対応しているため、商品一覧、ユーザー一覧、設定項目の選択画面など、さまざまな場面で利用できます。

この記事では、Windows FormsのListBoxを中心に、基本的な使い方から項目の追加・削除、選択モードの設定までをサンプルコード付きで解説します。WPFのListBoxとの違いについても紹介するため、C#でListBoxを使い始めたい方は順番に確認してみてください。

1. C#のListBoxとは

C#のListBoxとは、複数の項目を縦方向の一覧として表示するためのコントロールです。ユーザーは表示された項目の中から、1件または複数件を選択できます。

Windows FormsではSystem.Windows.Forms.ListBoxクラス、WPFではSystem.Windows.Controls.ListBoxクラスが使用されます。同じListBoxという名前でも、項目の管理方法やデータバインドの仕組みには違いがあります。

1-1. ListBoxでできること

ListBoxでは、主に次のような処理を実装できます。

  • 文字列や数値を一覧表示する

  • 項目を追加・削除する

  • 選択中の項目やインデックスを取得する

  • 複数の項目を選択できるようにする

  • 独自クラスのオブジェクトを表示する

  • データソースを設定して一覧を表示する

  • 選択が変更されたタイミングで処理を実行する

  • 項目を並べ替える

たとえば、都道府県をListBoxに表示する場合は、次のように記述します。

C#
listBox1.Items.Add("東京都");
listBox1.Items.Add("大阪府");
listBox1.Items.Add("愛知県");

追加した項目は、フォーム上のListBoxに上から順番に表示されます。

ListBoxの項目は、Itemsプロパティを通して操作します。選択中の項目はSelectedItem、選択位置はSelectedIndexから取得できます。

C#
object? selectedItem = listBox1.SelectedItem;

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

このように、一覧表示と選択処理を比較的少ないコードで実装できることがListBoxの特徴です。

1-2. ComboBoxやListViewとの違い

C#には、ListBoxと似た用途で使われるComboBoxListViewがあります。それぞれの特徴を理解し、画面の目的に合ったコントロールを選ぶことが重要です。

ListBoxは、すべての候補を一覧として常に表示します。項目数が多い場合はスクロールバーが表示されます。複数選択にも対応しているため、ユーザーに複数の候補を選ばせたい場合に適しています。

ComboBoxは、通常は選択中の項目だけを表示し、ボタンを押すと候補が展開されます。ListBoxよりも表示領域を節約できる点が特徴です。

ListViewは、名前、価格、在庫数など、複数の列を持つデータを表示したい場合に適しています。アイコン表示や詳細表示にも対応しています。

使い分けの目安は次のとおりです。

コントロール主な用途複数選択特徴
ListBox単純な項目一覧可能候補を常に一覧表示する
ComboBox1件の選択基本的に不可表示領域を節約できる
ListView複数列の一覧可能表形式やアイコン形式で表示できる

単純な文字列一覧から選択させる場合はListBox、画面をコンパクトにしたい場合はComboBox、複数列を表示したい場合はListViewを選ぶとよいでしょう。

1-3. Windows FormsとWPFのListBoxの違い

Windows FormsとWPFには、どちらにもListBoxがあります。ただし、クラスやプロパティ、データバインドの考え方が異なります。

Windows Formsでは、次の名前空間にあるListBoxを使用します。

C#
using System.Windows.Forms;

Windows FormsのListBoxでは、Items.AddItems.AddRangeを使って直接項目を追加できます。

C#
listBox1.Items.Add("項目1");
listBox1.Items.AddRange(new object[]
{
"項目2",
"項目3"
});

WPFでは、次の名前空間にあるListBoxを使用します。

C#
using System.Windows.Controls;

WPFでもItems.Addは利用できますが、一般的にはItemsSourceにコレクションを設定して使用します。

C#
var items = new List<string>
{
"項目1",
"項目2",
"項目3"
};

listBox1.ItemsSource = items;

WPFで項目の追加や削除を画面に自動反映したい場合は、ObservableCollection<T>を利用する方法が一般的です。

C#
using System.Collections.ObjectModel;

private readonly ObservableCollection<string> _items = new()
{
"項目1",
"項目2"
};

public MainWindow()
{
InitializeComponent();
listBox1.ItemsSource = _items;
}

private void AddButton_Click(object sender, RoutedEventArgs e)
{
_items.Add("項目3");
}

また、選択モードの列挙値にも違いがあります。

Windows Formsでは、次の値を使用します。

  • SelectionMode.None

  • SelectionMode.One

  • SelectionMode.MultiSimple

  • SelectionMode.MultiExtended

WPFでは、次の値を使用します。

  • SelectionMode.Single

  • SelectionMode.Multiple

  • SelectionMode.Extended

同じ名前のListBoxでもAPIが完全に同じではないため、Windows Forms用のコードをWPFへそのままコピーしないよう注意しましょう。

1-4. ListBoxが適している利用シーン

ListBoxは、ユーザーに複数の候補を見せながら選択してもらいたい画面に適しています。

代表的な利用シーンには、次のようなものがあります。

  • 都道府県やカテゴリの一覧

  • 商品やサービスの選択画面

  • ユーザーや担当者の一覧

  • ファイル名やフォルダ名の表示

  • アプリケーションの設定項目

  • 選択済みデータの確認画面

  • 複数項目を選択する検索条件画面

一方、数百件、数千件のデータを複数列で表示する場合は、ListBoxよりもDataGridViewListViewが適していることがあります。

項目数が多い場合は、検索機能や絞り込み機能を追加することも検討しましょう。

2. ListBoxの基本的な使い方

Windows FormsでListBoxを利用する方法には、Visual Studioのデザイナーから配置する方法と、C#のコードから生成する方法があります。

通常はデザイナーから配置する方法が簡単ですが、実行時にコントロールを動的に生成したい場合は、コードからListBoxを作成します。

2-1. フォームにListBoxを配置する方法

Visual StudioでWindows Formsアプリケーションを作成した場合は、ツールボックスからListBoxをフォームへドラッグ&ドロップして配置できます。

基本的な手順は次のとおりです。

  1. Visual StudioでWindows Formsプロジェクトを開く

  2. フォームをデザイナーで表示する

  3. ツールボックスから「ListBox」を探す

  4. ListBoxをフォーム上へドラッグ&ドロップする

  5. プロパティウィンドウで名前やサイズを設定する

ListBoxを配置すると、初期状態ではlistBox1のような名前が付けられます。実際のアプリケーションでは、用途が分かる名前へ変更するとコードを読みやすくできます。

たとえば、商品一覧を表示するListBoxであれば、次のような名前が考えられます。

productListBox

都道府県を表示する場合は、次のような名前にできます。

prefectureListBox

デザイナーから初期項目を登録することも可能です。プロパティウィンドウのItemsを選択し、コレクションエディターから項目を入力します。

ただし、データベースやファイルから取得した値を表示する場合は、フォームの読み込み時などにコードから項目を追加する方法が適しています。

C#
private void Form1_Load(object sender, EventArgs e)
{
prefectureListBox.Items.Add("東京都");
prefectureListBox.Items.Add("神奈川県");
prefectureListBox.Items.Add("千葉県");
}

フォームのLoadイベントに処理を記述すると、画面を表示するときに項目が追加されます。

2-2. コードからListBoxを生成する方法

ListBoxは、デザイナーを使わずにC#のコードから生成することもできます。

Windows FormsでListBoxを生成する基本的なコードは次のとおりです。

C#
using System;
using System.Drawing;
using System.Windows.Forms;

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

var listBox = new ListBox
{
Name = "productListBox",
Location = new Point(20, 20),
Size = new Size(200, 150)
};

listBox.Items.Add("ノートパソコン");
listBox.Items.Add("キーボード");
listBox.Items.Add("マウス");

Controls.Add(listBox);
}
}

Locationには、フォーム上でListBoxを配置する座標を指定します。Sizeには幅と高さを指定します。

最後にControls.Addを呼び出して、生成したListBoxをフォームのコントロールとして追加します。Controls.Addを忘れると、ListBoxのインスタンスを作成しても画面には表示されません。

フォーム内の複数のメソッドからListBoxを操作する場合は、ローカル変数ではなくフィールドとして宣言します。

C#
using System;
using System.Drawing;
using System.Windows.Forms;

public partial class Form1 : Form
{
private readonly ListBox _productListBox;

public Form1()
{
InitializeComponent();

_productListBox = new ListBox
{
Name = "productListBox",
Location = new Point(20, 20),
Size = new Size(200, 150)
};

Controls.Add(_productListBox);
}

private void AddProduct(string productName)
{
_productListBox.Items.Add(productName);
}
}

フィールドとして保持しておけば、ボタンのクリックイベントなどからも同じListBoxを操作できます。

2-3. Itemsプロパティの基本

Windows FormsのListBoxでは、Itemsプロパティを使って表示項目を管理します。

主な操作は次のとおりです。

C#
// 項目を追加する
listBox1.Items.Add("項目1");

// 指定位置に追加する
listBox1.Items.Insert(0, "先頭の項目");

// 項目を削除する
listBox1.Items.Remove("項目1");

// インデックスを指定して削除する
listBox1.Items.RemoveAt(0);

// すべての項目を削除する
listBox1.Items.Clear();

現在登録されている項目数は、Items.Countで取得できます。

C#
int itemCount = listBox1.Items.Count;
MessageBox.Show($"項目数は{itemCount}件です。");

インデックスを指定して項目を取得することも可能です。

C#
if (listBox1.Items.Count > 0)
{
object firstItem = listBox1.Items[0];
MessageBox.Show(firstItem.ToString());
}

ListBoxのインデックスは0から始まります。項目が3件ある場合、有効なインデックスは012です。

存在しないインデックスを指定するとArgumentOutOfRangeExceptionが発生するため、Items.Countを確認してからアクセスしましょう。

選択中の項目を取得する場合は、SelectedItemを使用します。

C#
if (listBox1.SelectedItem != null)
{
string selectedValue = listBox1.SelectedItem.ToString() ?? string.Empty;
MessageBox.Show($"選択値:{selectedValue}");
}
else
{
MessageBox.Show("項目が選択されていません。");
}

選択中のインデックスは、SelectedIndexで取得できます。

C#
int selectedIndex = listBox1.SelectedIndex;

if (selectedIndex >= 0)
{
MessageBox.Show($"選択位置:{selectedIndex}");
}

何も選択されていない場合、SelectedIndex-1になります。

2-4. 選択モードをSelectionModeで設定する方法

Windows FormsのListBoxでは、SelectionModeプロパティを使って項目の選択方法を設定できます。

1件だけ選択できるようにする場合は、SelectionMode.Oneを設定します。

C#
listBox1.SelectionMode = SelectionMode.One;

SelectionMode.Oneは標準的な選択モードです。別の項目を選択すると、それまで選択されていた項目は解除されます。

選択操作を無効にする場合は、SelectionMode.Noneを使用します。

C#
listBox1.SelectionMode = SelectionMode.None;

クリックするたびに項目の選択と解除を切り替えられるようにする場合は、SelectionMode.MultiSimpleを指定します。

C#
listBox1.SelectionMode = SelectionMode.MultiSimple;

CtrlキーやShiftキーを利用した一般的な複数選択を有効にする場合は、SelectionMode.MultiExtendedを指定します。

C#
listBox1.SelectionMode = SelectionMode.MultiExtended;

複数選択時は、SelectedItemではなくSelectedItemsを使って選択中のすべての項目を取得します。

C#
foreach (object item in listBox1.SelectedItems)
{
Console.WriteLine(item);
}

選択中のインデックスをすべて取得したい場合は、SelectedIndicesを使用します。

C#
foreach (int index in listBox1.SelectedIndices)
{
Console.WriteLine($"選択インデックス:{index}");
}

複数選択を有効にしている場合でも、SelectedItemSelectedIndexから取得できるのは、選択中の項目のうち1件だけです。選択項目をすべて処理する場合は、SelectedItemsまたはSelectedIndicesを利用しましょう。

3. ListBoxに項目を追加する方法

Windows FormsのListBoxへ項目を追加する方法には、Items.AddItems.AddRangeItems.Insertなどがあります。

項目を1件ずつ追加するのか、複数件を一括追加するのか、特定の位置へ挿入するのかによって使い分けます。

3-1. Items.Addで項目を1件追加する

ListBoxへ項目を1件追加する場合は、Items.Addを使用します。

C#
listBox1.Items.Add("りんご");

複数回呼び出すと、呼び出した順番で項目が追加されます。

C#
listBox1.Items.Add("りんご");
listBox1.Items.Add("みかん");
listBox1.Items.Add("バナナ");

Items.Addの戻り値は、追加された項目のインデックスです。

C#
int addedIndex = listBox1.Items.Add("ぶどう");

MessageBox.Show($"インデックス{addedIndex}に追加しました。");

文字列だけでなく、数値などのオブジェクトも追加できます。

C#
listBox1.Items.Add(100);
listBox1.Items.Add(DateTime.Now);

ListBoxは、項目を表示するときにオブジェクトのToStringメソッドを使用します。そのため、独自クラスを追加するときは、ToStringをオーバーライドするか、DisplayMemberを設定する必要があります。

追加後の項目を自動的に選択したい場合は、SelectedIndexを設定します。

C#
int index = listBox1.Items.Add("新しい項目");
listBox1.SelectedIndex = index;

末尾へ項目を追加したあと、その項目が見える位置までスクロールしたい場合は、TopIndexを設定できます。

C#
int index = listBox1.Items.Add("新しい項目");
listBox1.SelectedIndex = index;
listBox1.TopIndex = index;

3-2. Items.AddRangeで複数の項目を一括追加する

複数の項目をまとめて追加する場合は、Items.AddRangeを使用します。

C#
listBox1.Items.AddRange(new object[]
{
"東京都",
"神奈川県",
"千葉県",
"埼玉県"
});

文字列配列をあらかじめ用意して追加することもできます。

C#
string[] prefectures =
{
"東京都",
"神奈川県",
"千葉県",
"埼玉県"
};

listBox1.Items.AddRange(prefectures);

string[]object[]として扱えるため、Windows FormsのItems.AddRangeへ渡せます。

List<string>に保存されている項目を追加したい場合は、配列へ変換します。

C#
var products = new List<string>
{
"ノートパソコン",
"キーボード",
"マウス"
};

listBox1.Items.AddRange(products.ToArray());

Items.AddRangeはWindows Formsで複数項目を追加するための方法です。WPFのItemCollectionには同じ形式のAddRangeがないため、WPFではItemsSourceへコレクションを設定するか、ループでItems.Addを呼び出します。

WPFでコレクションを設定する例は次のとおりです。

C#
var products = new List<string>
{
"ノートパソコン",
"キーボード",
"マウス"
};

productListBox.ItemsSource = products;

Windows Formsで大量の項目を追加する場合は、描画を一時停止するBeginUpdateEndUpdateを利用すると、画面のちらつきを抑えられます。

C#
string[] items = Enumerable
.Range(1, 1000)
.Select(number => $"項目{number}")
.ToArray();

listBox1.BeginUpdate();

try
{
listBox1.Items.AddRange(items);
}
finally
{
listBox1.EndUpdate();
}

EndUpdateを確実に実行できるよう、tryfinallyを使用すると安全です。

3-3. Items.Insertで指定位置に項目を追加する

指定した位置へ項目を追加する場合は、Items.Insertを使用します。

C#
listBox1.Items.Insert(0, "先頭の項目");

第1引数に追加位置のインデックス、第2引数に追加する項目を指定します。

たとえば、次のListBoxがあるとします。

りんご
バナナ

インデックス1へ「みかん」を追加すると、りんごとバナナの間に挿入されます。

C#
listBox1.Items.Insert(1, "みかん");

実行後の順番は次のとおりです。

りんご
みかん
バナナ

末尾へ挿入する場合は、Items.Countを追加位置として指定できます。

C#
listBox1.Items.Insert(listBox1.Items.Count, "末尾の項目");

ただし、末尾へ追加するだけであれば、通常はItems.Addのほうが分かりやすいでしょう。

インデックスに負の値やItems.Countを超える値を指定すると例外が発生します。外部から受け取ったインデックスを利用する場合は、範囲を確認してください。

C#
int insertIndex = 2;
string newItem = "追加項目";

if (insertIndex >= 0 && insertIndex <= listBox1.Items.Count)
{
listBox1.Items.Insert(insertIndex, newItem);
}
else
{
MessageBox.Show("追加位置が正しくありません。");
}

3-4. TextBoxの入力値をListBoxに追加する

TextBoxへ入力された値をListBoxに追加する処理は、入力フォームなどでよく利用されます。

フォームに次のコントロールが配置されているものとします。

  • 入力用のTextBoxitemTextBox

  • 追加用のButtonaddButton

  • 表示用のListBoxitemListBox

追加ボタンのクリックイベントは、次のように実装できます。

C#
private void addButton_Click(object sender, EventArgs e)
{
string input = itemTextBox.Text.Trim();

if (string.IsNullOrWhiteSpace(input))
{
MessageBox.Show(
"追加する項目を入力してください。",
"入力エラー",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);

itemTextBox.Focus();
return;
}

itemListBox.Items.Add(input);

itemTextBox.Clear();
itemTextBox.Focus();
}

Trimを使うと、入力値の先頭と末尾にある空白を削除できます。string.IsNullOrWhiteSpaceを使えば、未入力や空白だけの文字列を除外できます。

項目を追加したあとにTextBox.Clearを呼び出すことで、入力欄を空にしています。さらにFocusを実行すると、ユーザーが続けて次の項目を入力しやすくなります。

Enterキーでも追加できるようにする場合は、TextBoxのKeyDownイベントを利用できます。

C#
private void itemTextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode != Keys.Enter)
{
return;
}

addButton.PerformClick();

e.SuppressKeyPress = true;
}

e.SuppressKeyPress = trueを設定すると、Enterキーを押したときの通知音や不要なキー入力を抑制できます。

3-5. 重複する項目を追加しない方法

同じ文字列をListBoxに重複して追加したくない場合は、Items.Containsで登録済みかどうかを確認します。

C#
string newItem = itemTextBox.Text.Trim();

if (string.IsNullOrWhiteSpace(newItem))
{
MessageBox.Show("追加する項目を入力してください。");
return;
}

if (itemListBox.Items.Contains(newItem))
{
MessageBox.Show("同じ項目がすでに登録されています。");
return;
}

itemListBox.Items.Add(newItem);

Items.Containsによる文字列の比較では、大文字と小文字が区別されます。そのため、次の2つは別の項目として扱われます。

C#
c#

大文字と小文字を区別せずに重複を確認する場合は、既存項目を走査して比較します。

C#
string newItem = itemTextBox.Text.Trim();

if (string.IsNullOrWhiteSpace(newItem))
{
MessageBox.Show("追加する項目を入力してください。");
return;
}

bool alreadyExists = itemListBox.Items
.Cast<object>()
.Any(item => string.Equals(
item?.ToString(),
newItem,
StringComparison.OrdinalIgnoreCase));

if (alreadyExists)
{
MessageBox.Show("同じ項目がすでに登録されています。");
return;
}

itemListBox.Items.Add(newItem);

全角・半角や空白の有無も統一したい場合は、ListBoxへ追加する前に文字列を正規化します。

C#
string NormalizeItem(string value)
{
return value.Trim().ToUpperInvariant();
}

ただし、表示する文字列そのものまで大文字へ変更したくない場合は、比較時だけ正規化した値を使用してください。

独自クラスをListBoxへ追加している場合は、Containsだけでは期待どおりに重複を判定できないことがあります。その場合は、IDなどの一意なプロパティを比較します。

C#
bool alreadyExists = productListBox.Items
.Cast<Product>()
.Any(product => product.Id == newProduct.Id);

if (!alreadyExists)
{
productListBox.Items.Add(newProduct);
}

3-6. 独自クラスのオブジェクトを項目として追加する方法

ListBoxには文字列だけでなく、独自クラスのオブジェクトも追加できます。

例として、商品を表すProductクラスを定義します。

C#
public class Product
{
public int Id { get; set; }

public string Name { get; set; } = string.Empty;

public decimal Price { get; set; }
}

このオブジェクトをそのままListBoxへ追加すると、既定ではクラス名が表示される可能性があります。

表示内容を指定する方法の1つは、ToStringをオーバーライドすることです。

C#
public class Product
{
public int Id { get; set; }

public string Name { get; set; } = string.Empty;

public decimal Price { get; set; }

public override string ToString()
{
return $"{Name}({Price:N0}円)";
}
}

オブジェクトは次のように追加します。

C#
productListBox.Items.Add(new Product
{
Id = 1,
Name = "ノートパソコン",
Price = 120000m
});

productListBox.Items.Add(new Product
{
Id = 2,
Name = "キーボード",
Price = 8000m
});

選択されたオブジェクトは、SelectedItemを目的の型へ変換して取得します。

C#
if (productListBox.SelectedItem is Product selectedProduct)
{
MessageBox.Show(
$"商品ID:{selectedProduct.Id}\n" +
$"商品名:{selectedProduct.Name}\n" +
$"価格:{selectedProduct.Price:N0}円");
}

ToStringを変更せず、特定のプロパティだけを表示したい場合は、DisplayMemberを使用します。

C#
productListBox.DisplayMember = nameof(Product.Name);

productListBox.Items.Add(new Product
{
Id = 1,
Name = "ノートパソコン",
Price = 120000m
});

この場合、ListBoxにはNameプロパティの値が表示されますが、SelectedItemから取得できるのは元のProductオブジェクトです。

データバインドを利用する場合は、DataSourceDisplayMemberValueMemberを設定します。

C#
var products = new List<Product>
{
new()
{
Id = 1,
Name = "ノートパソコン",
Price = 120000m
},
new()
{
Id = 2,
Name = "キーボード",
Price = 8000m
},
new()
{
Id = 3,
Name = "マウス",
Price = 3500m
}
};

productListBox.DisplayMember = nameof(Product.Name);
productListBox.ValueMember = nameof(Product.Id);
productListBox.DataSource = products;

選択された表示項目はSelectedItemValueMemberに指定した値はSelectedValueから取得できます。

C#
if (productListBox.SelectedItem is Product selectedProduct)
{
MessageBox.Show($"選択商品:{selectedProduct.Name}");
}

if (productListBox.SelectedValue is int productId)
{
MessageBox.Show($"商品ID:{productId}");
}

DataSourceを設定しているListBoxでは、Items.AddItems.Removeを直接実行できません。項目を変更したい場合は、バインド元のコレクションを操作します。

Windows Formsで追加・削除を画面へ反映させる場合は、BindingList<T>BindingSourceを使用すると便利です。

C#
using System.ComponentModel;

private readonly BindingList<Product> _products = new();
private readonly BindingSource _productSource = new();

private void Form1_Load(object sender, EventArgs e)
{
_products.Add(new Product
{
Id = 1,
Name = "ノートパソコン",
Price = 120000m
});

_products.Add(new Product
{
Id = 2,
Name = "キーボード",
Price = 8000m
});

_productSource.DataSource = _products;

productListBox.DisplayMember = nameof(Product.Name);
productListBox.ValueMember = nameof(Product.Id);
productListBox.DataSource = _productSource;
}

新しい商品を追加するときは、ListBoxではなくBindingList<Product>へ追加します。

C#
_products.Add(new Product
{
Id = 3,
Name = "マウス",
Price = 3500m
});

BindingList<T>へ追加した内容は、バインドされたListBoxにも反映されます。

4. ListBoxの項目を削除・クリアする方法

ListBoxの項目を削除する場合は、削除対象に応じてItems.RemoveまたはItems.RemoveAtを使用します。

すべての項目を削除する場合は、Items.Clearを使用します。

C#
listBox1.Items.Clear();

ユーザー操作で全件削除する場合は、確認メッセージを表示すると誤操作を防げます。

C#
private void clearButton_Click(object sender, EventArgs e)
{
if (listBox1.Items.Count == 0)
{
MessageBox.Show("削除する項目がありません。");
return;
}

DialogResult result = MessageBox.Show(
"すべての項目を削除しますか?",
"削除の確認",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);

if (result == DialogResult.Yes)
{
listBox1.Items.Clear();
}
}

DataSourceが設定されているListBoxでは、Items.Clearを直接呼び出せません。バインド元のコレクションをクリアしてください。

C#
_products.Clear();

4-1. Items.Removeで指定した項目を削除する

Items.Removeは、項目の値やオブジェクトを指定して削除するメソッドです。

C#
listBox1.Items.Remove("りんご");

指定した項目が存在する場合は、その項目が削除されます。存在しない場合でも例外は発生しません。

削除前に項目の存在を確認したい場合は、Items.Containsを使用します。

C#
string targetItem = "りんご";

if (listBox1.Items.Contains(targetItem))
{
listBox1.Items.Remove(targetItem);
MessageBox.Show("項目を削除しました。");
}
else
{
MessageBox.Show("削除対象の項目が見つかりません。");
}

選択中の項目をItems.Removeで削除する場合は、SelectedItemnullでないことを確認します。

C#
private void removeButton_Click(object sender, EventArgs e)
{
object? selectedItem = listBox1.SelectedItem;

if (selectedItem == null)
{
MessageBox.Show("削除する項目を選択してください。");
return;
}

listBox1.Items.Remove(selectedItem);
}

独自クラスのオブジェクトも同じ方法で削除できます。

C#
if (productListBox.SelectedItem is Product selectedProduct)
{
productListBox.Items.Remove(selectedProduct);
}

ただし、データバインドしている場合はListBoxのItems.Removeではなく、バインド元のコレクションから削除します。

C#
if (productListBox.SelectedItem is Product selectedProduct)
{
_products.Remove(selectedProduct);
}

複数選択された項目を削除する場合は、削除対象を一度配列へコピーしてから処理します。

C#
object[] selectedItems = listBox1.SelectedItems
.Cast<object>()
.ToArray();

foreach (object item in selectedItems)
{
listBox1.Items.Remove(item);
}

SelectedItemsを直接列挙しながらListBoxの内容を変更すると、コレクションの状態が変化して正しく処理できない可能性があります。先にToArrayで削除対象を固定しておくと安全です。

4-2. Items.RemoveAtで選択中の項目を削除する

Items.RemoveAtは、インデックスを指定して項目を削除するメソッドです。

C#
listBox1.Items.RemoveAt(0);

このコードでは、ListBoxの先頭にある項目を削除します。

選択中の項目を削除する場合は、SelectedIndexを使用します。

C#
private void removeButton_Click(object sender, EventArgs e)
{
int selectedIndex = listBox1.SelectedIndex;

if (selectedIndex < 0)
{
MessageBox.Show("削除する項目を選択してください。");
return;
}

listBox1.Items.RemoveAt(selectedIndex);
}

何も選択されていない場合、SelectedIndex-1です。RemoveAt(-1)を実行すると例外が発生するため、必ず選択状態を確認してください。

項目を削除したあと、次の項目を自動的に選択する場合は、削除後の項目数を確認してSelectedIndexを設定します。

C#
private void removeButton_Click(object sender, EventArgs e)
{
int selectedIndex = listBox1.SelectedIndex;

if (selectedIndex < 0)
{
MessageBox.Show("削除する項目を選択してください。");
return;
}

listBox1.Items.RemoveAt(selectedIndex);

if (listBox1.Items.Count == 0)
{
return;
}

int nextIndex = Math.Min(selectedIndex, listBox1.Items.Count - 1);
listBox1.SelectedIndex = nextIndex;
}

最後の項目を削除した場合は、削除前のインデックスが削除後の範囲を超えるため、Math.Minを使って有効なインデックスへ調整しています。

複数選択された項目をRemoveAtで削除する場合は、インデックスが大きい順に処理します。

C#
int[] selectedIndices = listBox1.SelectedIndices
.Cast<int>()
.OrderByDescending(index => index)
.ToArray();

foreach (int index in selectedIndices)
{
listBox1.Items.RemoveAt(index);
}

小さいインデックスから削除すると、後ろにある項目のインデックスがずれてしまいます。たとえば、インデックス1を削除すると、それまでインデックス2だった項目が1へ移動します。

そのため、複数の項目をインデックスで削除するときは、後ろから前へ向かって処理することが重要です。

RemoveRemoveAtの違いは、削除対象の指定方法です。

C#
// 値またはオブジェクトを指定して削除
listBox1.Items.Remove("りんご");

// インデックスを指定して削除
listBox1.Items.RemoveAt(0);

削除するオブジェクトが分かっている場合はRemove、削除位置が分かっている場合はRemoveAtを使用するとよいでしょう。

まとめ

C#のListBoxは、複数の項目を一覧表示し、ユーザーに1件または複数件を選択してもらうためのコントロールです。

Windows Formsでは、Itemsプロパティを通して項目を操作します。1件追加する場合はItems.Add、複数件を一括追加する場合はItems.AddRange、指定位置へ追加する場合はItems.Insertを使用します。

項目を削除するときは、値やオブジェクトを指定するItems.Removeと、インデックスを指定するItems.RemoveAtを使い分けます。すべての項目を削除する場合はItems.Clearを利用できます。

選択中の値はSelectedItem、選択位置はSelectedIndexから取得できます。複数選択時は、SelectedItemsまたはSelectedIndicesを使用することがポイントです。

独自クラスのオブジェクトを表示する場合は、ToStringのオーバーライドやDisplayMemberの設定を利用できます。データバインドを行う場合は、DataSourceDisplayMemberValueMemberを設定し、追加や削除はバインド元のコレクションに対して行います。

ListBoxの基本的なプロパティとメソッドを理解すれば、商品一覧、ユーザー選択、設定画面など、さまざまなWindows Formsアプリケーションへ応用できます。