Desktopアプリ開発で、一番悩むのが、dataGridView関係とcomboBoxかと思います。今回は、コンボボックスの一例を紹介したいと思います。WinFormsには、有料のコンポーネントが数多くありますが、結構なお値段なのと、私の長年の経験として、意外とバグがあったりして、それを補完しながらの開発も結構、工数が増えます。
今回は、コンボボックスについて1パターンを紹介したいと思います。3列のコンボボックスで、データをList<DataCombo>形式で渡して、戻り値として、選択したID(1列目)とNAME(二列目)を取得するユーザーコントロールを作りました。(下記イメージ)
CustomCombo.cs (ユーザーコントロール)クラスを一つ作成します。

↓ユーザーコントロール(コンボボックス)のClassソース
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using static System.Windows.Forms.VisualStyles.VisualStyleElement; namespace WinForms01 { /// -------------------------------------------------------------------------------- /// <summary> /// 作成: モバイルステーション 2024.02.23 M.SAGARA /// </summary> /// -------------------------------------------------------------------------------- public partial class CustomCombo : UserControl { private System.Windows.Forms.TextBox textBox; private System.Windows.Forms.Button dropDownButton; private Form dropDownForm; private DataGridView dataGridView; public string sNAME = ""; // カスタムイベントの定義 public event EventHandler TextBoxTextChanged; /// -------------------------------------------------------------------------------- /// <summary> /// コンストラクター /// </summary> /// -------------------------------------------------------------------------------- public CustomCombo() { InitializeComponent(); InitializeCustomComboBox(); InitializeDropDownFormWithDataGridView(); // dataGridView.CellClickイベントを購読 this.dataGridView.CellClick += MyTextBox_TextChanged; } /// -------------------------------------------------------------------------------- /// <summary> /// 外部からデータを受け取るためのメソッド /// ※DataCombo (Id,Name,Descripton) /// </summary> /// <param name="items"></param> /// -------------------------------------------------------------------------------- public void SetData(List<DataCombo> items) { dataGridView.DataSource = items; dataGridView.Refresh(); } // TextBoxのTextChangedイベントハンドラ private void MyTextBox_TextChanged(object sender, EventArgs e) { // カスタムイベントを発火 TextBoxTextChanged?.Invoke(sender, e); } // TextBoxのテキストを外部から取得するためのプロパティ public string TextBoxText { get { return textBox.Text; } set { textBox.Text = value; } } private void InitializeCustomComboBox() { // TextBoxの設定 textBox = new System.Windows.Forms.TextBox { Dock = DockStyle.Fill, ReadOnly = true }; this.Controls.Add(textBox); // ドロップダウンボタンの設定 dropDownButton = new System.Windows.Forms.Button { Dock = DockStyle.Right, Text = "▼", Width = 24, // ボタンの幅を24ピクセルに設定 Height = 24 }; this.Controls.Add(dropDownButton); dropDownButton.Click += (s, e) => ShowDropDownForm(); // コントロールの高さ調整 // ボタンの高さを調整する場合は、CustomComboBoxControlのサイズ調整を行う this.Height = textBox.Height; // コントロールの高さを調整 } private void InitializeDropDownFormWithDataGridView() { // dataGridViewの設定 dataGridView = new DataGridView { Dock = DockStyle.Fill, SelectionMode = DataGridViewSelectionMode.FullRowSelect, AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells, AllowUserToResizeRows = false, RowHeadersVisible = false, // 行ヘッダーを非表示に設定 ReadOnly = true, AllowUserToAddRows = false }; // DataGridViewの行のデフォルトの高さを設定 dataGridView.RowTemplate.Height = 18; dropDownForm = new Form { FormBorderStyle = FormBorderStyle.None, StartPosition = FormStartPosition.Manual, Size = new Size(300, 300), // 初期サイズ設定 TopMost = true }; dropDownForm.Controls.Add(dataGridView); dropDownForm.Deactivate += (s, e) => dropDownForm.Hide(); dataGridView.CellClick += DataGridView_CellClick; } /// -------------------------------------------------------------------------------- /// <summary> /// dataGridViewの部分が表示されるときの、イベント /// </summary> /// -------------------------------------------------------------------------------- private void ShowDropDownForm() { // 現在のスクリーンの作業領域を取得(タスクバーなどを除いた領域) Rectangle screenWorkingArea = Screen.GetWorkingArea(this); // ComboBoxのスクリーン上の位置を取得 Point comboBoxScreenLocation = this.textBox.PointToScreen(Point.Empty); // Formの予定表示位置(ComboBoxの直下)を計算 int formX = comboBoxScreenLocation.X; int formY = comboBoxScreenLocation.Y + textBox.Height; // Formの予定表示位置が画面下からはみ出るかどうかを確認 bool isBelowScreen = (formY + dropDownForm.Height) > screenWorkingArea.Bottom; if (dropDownForm.Visible) { dropDownForm.Hide(); } else { if (isBelowScreen) { // 画面下からはみ出る場合、FormをComboBoxの上に表示 formY = comboBoxScreenLocation.Y - dropDownForm.Height; } // Formの位置を設定して表示 dropDownForm.Location = new Point(formX, formY); dropDownForm.Show(); } // dataGridViewの列幅の計算 int totalWidth = 0; foreach (DataGridViewColumn column in dataGridView.Columns) { totalWidth += column.Width; } dropDownForm.Width = totalWidth + 20; } // EOF ShowDropDownForm /// -------------------------------------------------------------------------------- /// <summary> /// コンボボックスの行選択時、イベント /// </summary> /// <param name="sender"></param> /// <param name="e"></param> /// -------------------------------------------------------------------------------- private void DataGridView_CellClick(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex >= 0) { if (dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value != null) { // テキストボックスに選択値のセット //textBox.Text = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString(); textBox.Text = dataGridView.Rows[e.RowIndex].Cells[0].Value.ToString(); sNAME = dataGridView.Rows[e.RowIndex].Cells[1].Value.ToString(); } dropDownForm.Hide(); } } } // EOF Class } // EOF namespace
Form(コンボボックスを配置した)のソース
/// -------------------------------------------------------------------------------- /// <summary> /// フォーム読み込み時、イベント /// </summary> /// <param name="sender"></param> /// <param name="e"></param> /// -------------------------------------------------------------------------------- private void FrmMain_Load(object sender, EventArgs e) { // コンボボックスのデータの準備 List<DataCombo> items = new List<DataCombo>(); for (int i = 0; i < 100; i++) { DataCombo row = new DataCombo { Id = i.ToString("D4"), Name = "Item " + i.ToString(), Description = "Description " + i.ToString() }; items.Add(row); }; customCombo1.SetData(items); boLoading = false; } /// -------------------------------------------------------------------------------- /// <summary> /// コンボボックスで、行選択時イベント /// </summary> /// <param name="sender"></param> /// <param name="e"></param> /// -------------------------------------------------------------------------------- private void customCombo1_TextBoxTextChanged(object sender, EventArgs e) { // コンボボックスで、選択された行の、2列目の取得 lblComboName.Text = customCombo1.sNAME; }
