はじめに
System.Windows.Forms.DataGrid
コントロール(以下DataGrid
)にComboBox
コントロールを表示するもっとも単純な方法は、マイクロソフトサポート技術情報の「[323167 - HOWTO] Windows フォームの DataGrid コントロールに ComboBox コントロールを追加する方法」(現在は閲覧できません)にあるように、DataGrid
にComboBox
をのせ、DataGrid
のイベントを利用してComboBox
を操作するという方法でしょう。しかし、DataGridColumnStyle
クラス(System.Windows.Forms
名前空間)から派生した独自の列クラスを作成することにより、ComboBox
を管理するというやり方の方がよりスマートです。ここでは後者の方法について解説し、実際にComboBox
を管理する列クラス(DataGridComboBoxColumn
クラス)のコード例を示します。
対象読者
System.Windows.Forms.DataGrid
コントロールに任意のコントロールを追加する方法を知りたいという方を対象としています。とりあえずComboBox
を追加したいという方は、「DataGridComboBoxColumnの使用法」からお読みください。ここでは.NETプログラミングの基本的な事柄については説明しませんので、不明な点はMSDNライブラリ等で調べてください。
必要な環境
サンプルはVisual Studio .NET 2003で作成され、.NET Framework 1.1で動作確認をしていますが、.NET Framework 1.0でも問題なく動作するでしょう。
独自の列クラスの作成
DataGrid
にデータをどのように表示し、ユーザーがどのように編集できるようにするかという管理を行うのが、DataGridColumnStyle
オブジェクトです。DataGridColumnStyle
クラスは抽象クラスですので、実際にはその派生クラスのインスタンスということになります。.NET FrameworkではDataGridColumnStyle
の派生クラスとして、TextBox
を管理するDataGridTextBoxColumn
クラスと、CheckBox
を表示するDataGridBoolColumn
クラスの2つが用意されています(.NET Farmework 1.1現在。将来はもっと増え、ComboBox
を管理するクラスも追加されるでしょう)。
.NET Frameworkで用意されている列クラスはこの2つだけですので、ComboBox
やその他のコントロールを使った列スタイルをDataGrid
で使用したい時は、独自で列クラスを作成しなければなりません。この独自の列クラスももちろんDataGridColumnStyle
を継承する必要があります。
DataGridColumnStyle
は抽象クラスですので、派生クラスでは最低でも次の抽象メソッドをオーバーライドする必要があります。
メソッド | 説明 |
Abort | 編集操作が中断される時([Escape]キーが押された時や、DataGrid.EndEdit がshouldAbort パラメータTrueで呼び出された時など)に実行されます。通常はここで、編集中の値を元に戻し、編集に用いたコントロールを非表示にします。 |
Commit | 編集が完了する時(現在のセルが別のセルに変わる時など)に実行されます。通常はここで、SetColumnValueAtRow メソッドによりセルの値を更新し、編集に用いたコントロールを非表示にします。 |
Edit | 指定されたセルが編集状態になる時に実行されます。通常はここで、編集に用いるコントロールを表示します。初期値は、GetColumnValueAtRow メソッドにより取得します。 |
GetMinimumHeight | 行の最小の高さを返すようにします。 |
GetPreferredHeight | 指定された値を表示するのに適切な行の高さを返すようにします。ユーザーが行の境界線をダブルクリックして列の高さが自動的に変更される時などに使用されます。 |
GetPreferredSize | 指定された値を表示するのに適切なサイズを返すようにします。ユーザーが列の境界線をダブルクリックして列の幅が自動的に変更される時などに使用されます。 |
Paint | 指定されたセルを描画します(境界線を除く)。例えば文字列を表示する時は、GetColumnValueAtRow メソッドにより値を取得し、表示用の文字列に変換し、Graphics.DrawString メソッドにより実際に描画します。もちろん図形や画像を描画してもOKです。 |
このようにDataGridColumnStyle
クラスを直接継承して列クラスを作成するのが基本ですが、既存の列クラスを継承した方が便利な場合もあります。特にDataGridTextBoxColumn
クラスでは書式等を指定してデータを表示させる処理がすでに実装されていますので、この部分のコードを書く手間が省けます。大雑把に言えば、DataGridComboBoxColumn
はDataGridTextBoxColumn
のTextBox
をComboBox
に置き換えたものですので、DataGridTextBoxColumn
を継承する利点は多いと考えられます。よってここではDataGridTextBoxColumn
クラスを継承することにより、DataGridComboBoxColumn
クラスを作成することにします。
DataGridTextBoxColumn
クラスを継承してDataGridComboBoxColumn
クラスを作成すると、セルでのデータの表示はDataGridTextBoxColumn
と全く同じで構いませんので、Paint
メソッドを実装する必要がなくなります。ただし、Edit
やCommit
メソッド等は、DataGridColumnStyle
から派生する場合と同様にオーバーライドし、適当な処理を行わなければなりません。また、ComboBox
の親コントロールをDataGrid
とするために、SetDataGridInColumn
メソッドをオーバーライドすることも必要です。
さらに、DataGridComboBoxColumn
では表示に使う値と実際の値が異なりますので(詳しくは下の使用法をご覧ください)、SetColumnValueAtRow
及びGetColumnValueAtRow
メソッドをオーバーライドし、セルに適切な値が表示されるようにします(これとは別の方法も考えられます)。
この他にも細かい処理が必要ですが、詳しくはサンプルのソースコードをご覧ください。
DataGridComboBoxColumnの使用法
ここからは、DataGridComboBoxColumn
の使用法を説明します。サンプルのソースコードに実際の使用例がありますので、そちらもあわせてご覧ください。
- このページからリンクされているデモサンプルをダウンロードし、書庫ファイル内の「DataGridComboBoxColumn.dll」を適当な場所に展開します。
DataGridComboBoxColumn
クラスを使用したいプロジェクトを開き、「DataGridComboBoxColumn.dll」を参照に追加します。詳しくはMSDNの「参照の追加と削除」をご覧ください。- DataGrid内で
ComboBox
を表示したい列の列スタイルにDataGridComboBoxColumn
オブジェクトを使用するために、次のようなコードを書きます(フォームのLoad
イベントハンドラ等にお書きください)。ここでは、フォームに「DataGrid1」という名前のDataGrid
コントロールが配置されているものとします。 - 以上で終了です。成功すれば、上の図のようになります。
//DataGridに表示するDataTableの作成 DataTable dt = new DataTable("DataTable1"); //列の追加 dt.Columns.Add("Column1", typeof(int)); //行の追加 dt.Rows.Add(new object[] {5}); dt.Rows.Add(new object[] {9}); dt.Rows.Add(new object[] {3}); //DataGridで表示するデータソースに設定 DataGrid1.DataSource = dt; //DataGridTableStyleの作成 DataGridTableStyle ts = new DataGridTableStyle(); ts.MappingName = "DataTable1"; //DataGridComboBoxColumnで使用するDataTableの作成 //"DisplayMember"列はComboBoxに表示される値 //"ValueMember"列は実際の値 DataTable comboSorce = new DataTable("ComboBox"); comboSorce.Columns.Add("DisplayMember", typeof(string)); comboSorce.Columns.Add("ValueMember", typeof(int)); comboSorce.Rows.Add(new object[] {"一", 1}); comboSorce.Rows.Add(new object[] {"二", 2}); comboSorce.Rows.Add(new object[] {"三", 3}); comboSorce.Rows.Add(new object[] {"四", 4}); comboSorce.Rows.Add(new object[] {"五", 5}); comboSorce.Rows.Add(new object[] {"六", 6}); comboSorce.Rows.Add(new object[] {"七", 7}); comboSorce.Rows.Add(new object[] {"八", 8}); comboSorce.Rows.Add(new object[] {"九", 9}); //DataGridComboBoxColumnの作成 Dobon.Forms.DataGridComboBoxColumn cbc = new Dobon.Forms.DataGridComboBoxColumn( comboSorce.DefaultView,"DisplayMember","ValueMember"); //表示される値と実際の値が同じでよければ、次のようにもできる //Dobon.Samples.Forms.DataGridComboBoxColumn cbc = // new Dobon.Samples.Forms.DataGridComboBoxColumn( // comboSorce.DefaultView, "ValueMember"); cbc.MappingName = "Column1"; cbc.HeaderText = "数字"; //列スタイルの追加 ts.GridColumnStyles.Add(cbc); //テーブルスタイルの追加 DataGrid1.TableStyles.Add(ts);
'DataGridに表示するDataTableの作成 Dim dt As New DataTable("DataTable1") '列の追加 dt.Columns.Add("Column1", GetType(Integer)) '行の追加 dt.Rows.Add(New Object() {5}) dt.Rows.Add(New Object() {9}) dt.Rows.Add(New Object() {3}) 'DataGridで表示するデータソースに設定 DataGrid1.DataSource = dt 'DataGridTableStyleの作成 Dim ts As New DataGridTableStyle ts.MappingName = "DataTable1" 'DataGridComboBoxColumnで使用するDataTableの作成 '"DisplayMember"列はComboBoxに表示される値 '"ValueMember"列は実際の値 Dim comboSorce As New DataTable("ComboBox") comboSorce.Columns.Add("DisplayMember", GetType(String)) comboSorce.Columns.Add("ValueMember", GetType(Integer)) comboSorce.Rows.Add(New Object() {"一", 1}) comboSorce.Rows.Add(New Object() {"二", 2}) comboSorce.Rows.Add(New Object() {"三", 3}) comboSorce.Rows.Add(New Object() {"四", 4}) comboSorce.Rows.Add(New Object() {"五", 5}) comboSorce.Rows.Add(New Object() {"六", 6}) comboSorce.Rows.Add(New Object() {"七", 7}) comboSorce.Rows.Add(New Object() {"八", 8}) comboSorce.Rows.Add(New Object() {"九", 9}) 'DataGridComboBoxColumnの作成 Dim cbc As New Dobon.Forms.DataGridComboBoxColumn( _ comboSorce.DefaultView, "DisplayMember", "ValueMember") '表示される値と実際の値が同じでよければ、次のようにもできる 'Dim cbc As New Dobon.Forms.DataGridComboBoxColumn( _ ' comboSorce.DefaultView, "ValueMember") cbc.MappingName = "Column1" cbc.HeaderText = "数字" '列スタイルの追加 ts.GridColumnStyles.Add(cbc) 'テーブルスタイルの追加 DataGrid1.TableStyles.Add(ts)
DataGridComboBoxColumn
クラスのコンストラクタには3つのパラメータがあり、ComboBox
のDataSource
と、DisplayMember
、ValueMember
をここで指定します。DisplayMember
にはComboBox
とDataGrid
で表示される値を指定し、ValueMember
には実際の値を指定します。上のコードでは、1から9までの数字を漢数字で表示されるようにしています。DataGridComboBoxColumnの仕様
最後に上記以外のDataGridComboBoxColumn
クラスの仕様を示します。
- コンボボックスの
DropDownStyle
プロパティはComboBoxStyle.DropDownList
です。 ReadOnly
の時は、コンボボックスが表示されません。ComboBox
のDataSource
をDataGrid
のDataSource
と同じにすると、不都合があるかもしれません。ComboBox
をキーボードで操作することはできません。ComboBox
のValueMember
に登録されていないデータがDataGrid
で使用されている場合、「DBNull」として表示されます。
おまけ - DataGridButtonColumnクラス
おまけとして、DataGridButtonColumn
クラスを付けました(あくまでただのおまけと思ってください)。このクラスは、DataGridにButtonコントロールを表示する列クラスです。DataGrid
にButton
を表示する方法もComboBox
の場合と同じだと思われるかもしれませんが、Button
の場合はEdit
メソッドでコントロールを表示していると、1回目のクリックでButton
を表示し、2回目のクリックでようやく本当にButton
をクリックできるという、好ましくない挙動となってしまいます。よってDataGridButtonColumn
クラスでは、実際にはButton
コントロールを使用せずに、ただButton
をセルに描画しているだけです。.NET FrameworkのDataGridBoolColumn
はCheckBox
を表示しますが、やはりCheckBox
コントロールを使用しているわけではありません。さらに詳しくは、メールマガジン「.NETプログラミング研究」第37号「DataGridにLinkLabelを表示するには?」をご覧ください。
まとめ
ここではSystem.Windows.Forms.DataGrid
コントロールにComboBox
コントロールを表示するための列クラスの作成法を紹介しました。ポイントは、以下の通りです。
System.Windows.Forms.DataGrid
コントロールに任意のコントロールを追加するには、DataGridColumnStyle
クラスから派生した列クラスを作成し、使用すると良い。DataGridColumnStyle
クラスは抽象クラスなので、すべての抽象メンバをオーバーライドしなければならない。詳細は、「表1.DataGridColumnStyleクラスの抽象メソッド」にある。DataGridColumnStyle
を直接継承するよりも、DataGridTextBoxColumn
などの既存の列クラスを継承したほうが手間が省ける場合もある。
参考資料
- DOBON.NET 『.NET Tips - DataGridでComboBoxを使う』
- Akadia AG 『How to put a combobox in a column of a datagrid ?』
- GotDotNet 『GotDotNet User Sample: DataGridComboBoxColumn』
- C# Corner 『Generating Combo Box in DataGrid Columns』 Sudhakar Jalli 著
- DataGridExtensions.DataGridComboBoxColumnStyle by Mark Boulter(Microsoft)
- MSDN Magazine 『DataGrid: Tailor Your DataGrid Apps Using Table Style and Custom Column Style Objects』 Kristy Saunders 著、2003年8月
- MSDNライブラリ 『Styling with the DataGridColumnStyle, Part 2』 Chris Sano 著、2005年1月