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;
}