SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

DataGridにComboBoxを表示可能な列を作る

DataGridColumnStyleの派生クラスによる独自列クラスの作成法


ダウンロード バイナリ (11.0 KB)
ダウンロード ソース (46.8 KB)

DataGridColumnStyleクラスから派生した独自の列クラスを作成することにより、DataGridの列にComboBoxを表示する方法。

DataGridにComboBoxを表示
DataGridにComboBoxを表示

はじめに

 System.Windows.Forms.DataGridコントロール(以下DataGrid)にComboBoxコントロールを表示するもっとも単純な方法は、マイクロソフトサポート技術情報の「[323167 - HOWTO] Windows フォームの DataGrid コントロールに ComboBox コントロールを追加する方法」(現在は閲覧できません)にあるように、DataGridComboBoxをのせ、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は抽象クラスですので、派生クラスでは最低でも次の抽象メソッドをオーバーライドする必要があります。

表1.DataGridColumnStyleクラスの抽象メソッド
メソッド説明
Abort編集操作が中断される時([Escape]キーが押された時や、DataGrid.EndEditshouldAbortパラメータTrueで呼び出された時など)に実行されます。通常はここで、編集中の値を元に戻し、編集に用いたコントロールを非表示にします。
Commit編集が完了する時(現在のセルが別のセルに変わる時など)に実行されます。通常はここで、SetColumnValueAtRowメソッドによりセルの値を更新し、編集に用いたコントロールを非表示にします。
Edit指定されたセルが編集状態になる時に実行されます。通常はここで、編集に用いるコントロールを表示します。初期値は、GetColumnValueAtRowメソッドにより取得します。
GetMinimumHeight行の最小の高さを返すようにします。
GetPreferredHeight指定された値を表示するのに適切な行の高さを返すようにします。ユーザーが行の境界線をダブルクリックして列の高さが自動的に変更される時などに使用されます。
GetPreferredSize指定された値を表示するのに適切なサイズを返すようにします。ユーザーが列の境界線をダブルクリックして列の幅が自動的に変更される時などに使用されます。
Paint指定されたセルを描画します(境界線を除く)。例えば文字列を表示する時は、GetColumnValueAtRowメソッドにより値を取得し、表示用の文字列に変換し、Graphics.DrawStringメソッドにより実際に描画します。もちろん図形や画像を描画してもOKです。

 このようにDataGridColumnStyleクラスを直接継承して列クラスを作成するのが基本ですが、既存の列クラスを継承した方が便利な場合もあります。特にDataGridTextBoxColumnクラスでは書式等を指定してデータを表示させる処理がすでに実装されていますので、この部分のコードを書く手間が省けます。大雑把に言えば、DataGridComboBoxColumnDataGridTextBoxColumnTextBoxComboBoxに置き換えたものですので、DataGridTextBoxColumnを継承する利点は多いと考えられます。よってここではDataGridTextBoxColumnクラスを継承することにより、DataGridComboBoxColumnクラスを作成することにします。

 DataGridTextBoxColumnクラスを継承してDataGridComboBoxColumnクラスを作成すると、セルでのデータの表示はDataGridTextBoxColumnと全く同じで構いませんので、Paintメソッドを実装する必要がなくなります。ただし、EditCommitメソッド等は、DataGridColumnStyleから派生する場合と同様にオーバーライドし、適当な処理を行わなければなりません。また、ComboBoxの親コントロールをDataGridとするために、SetDataGridInColumnメソッドをオーバーライドすることも必要です。

 さらに、DataGridComboBoxColumnでは表示に使う値と実際の値が異なりますので(詳しくは下の使用法をご覧ください)、SetColumnValueAtRow及びGetColumnValueAtRowメソッドをオーバーライドし、セルに適切な値が表示されるようにします(これとは別の方法も考えられます)。

 この他にも細かい処理が必要ですが、詳しくはサンプルのソースコードをご覧ください。

DataGridComboBoxColumnの使用法

 ここからは、DataGridComboBoxColumnの使用法を説明します。サンプルのソースコードに実際の使用例がありますので、そちらもあわせてご覧ください。

  1. このページからリンクされているデモサンプルをダウンロードし、書庫ファイル内の「DataGridComboBoxColumn.dll」を適当な場所に展開します。
  2. DataGridComboBoxColumnクラスを使用したいプロジェクトを開き、「DataGridComboBoxColumn.dll」を参照に追加します。詳しくはMSDNの「参照の追加と削除」をご覧ください。
  3. DataGrid内でComboBoxを表示したい列の列スタイルにDataGridComboBoxColumnオブジェクトを使用するために、次のようなコードを書きます(フォームのLoadイベントハンドラ等にお書きください)。ここでは、フォームに「DataGrid1」という名前のDataGridコントロールが配置されているものとします。
  4. C#
    //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);
    
    VB.NET
    '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つのパラメータがあり、ComboBoxDataSourceと、DisplayMemberValueMemberをここで指定します。DisplayMemberにはComboBoxDataGridで表示される値を指定し、ValueMemberには実際の値を指定します。上のコードでは、1から9までの数字を漢数字で表示されるようにしています。
    DataGrid内のセルに表示されたComboBox
    DataGrid内のセルに表示されたComboBox
    なお列スタイルを使うにはちょっとしたコツがいるかもしれません。列スタイルの使用法に関しては、「DOBON.NET .NET Tips - DataGridの列の幅を変更する」などを参考にしてください。
  5. 以上で終了です。成功すれば、上の図のようになります。

DataGridComboBoxColumnの仕様

 最後に上記以外のDataGridComboBoxColumnクラスの仕様を示します。

  • コンボボックスのDropDownStyleプロパティはComboBoxStyle.DropDownListです。
  • ReadOnlyの時は、コンボボックスが表示されません。
  • ComboBoxDataSourceDataGridDataSourceと同じにすると、不都合があるかもしれません。
  • ComboBoxをキーボードで操作することはできません。
  • ComboBoxValueMemberに登録されていないデータがDataGridで使用されている場合、「DBNull」として表示されます。

おまけ - DataGridButtonColumnクラス

 おまけとして、DataGridButtonColumnクラスを付けました(あくまでただのおまけと思ってください)。このクラスは、DataGridにButtonコントロールを表示する列クラスです。DataGridButtonを表示する方法もComboBoxの場合と同じだと思われるかもしれませんが、Buttonの場合はEditメソッドでコントロールを表示していると、1回目のクリックでButtonを表示し、2回目のクリックでようやく本当にButtonをクリックできるという、好ましくない挙動となってしまいます。よってDataGridButtonColumnクラスでは、実際にはButtonコントロールを使用せずに、ただButtonをセルに描画しているだけです。.NET FrameworkのDataGridBoolColumnCheckBoxを表示しますが、やはりCheckBoxコントロールを使用しているわけではありません。さらに詳しくは、メールマガジン「.NETプログラミング研究」第37号「DataGridにLinkLabelを表示するには?」をご覧ください。

まとめ

 ここではSystem.Windows.Forms.DataGridコントロールにComboBoxコントロールを表示するための列クラスの作成法を紹介しました。ポイントは、以下の通りです。

  • System.Windows.Forms.DataGridコントロールに任意のコントロールを追加するには、DataGridColumnStyleクラスから派生した列クラスを作成し、使用すると良い。
  • DataGridColumnStyleクラスは抽象クラスなので、すべての抽象メンバをオーバーライドしなければならない。詳細は、「表1.DataGridColumnStyleクラスの抽象メソッド」にある。
  • DataGridColumnStyleを直接継承するよりも、DataGridTextBoxColumnなどの既存の列クラスを継承したほうが手間が省ける場合もある。

参考資料

  1. DOBON.NET 『.NET Tips - DataGridでComboBoxを使う』
  2. Akadia AG 『How to put a combobox in a column of a datagrid ?』
  3. GotDotNet 『GotDotNet User Sample: DataGridComboBoxColumn』
  4. C# Corner 『Generating Combo Box in DataGrid Columns』 Sudhakar Jalli 著
  5. DataGridExtensions.DataGridComboBoxColumnStyle by Mark Boulter(Microsoft)
  6. MSDN Magazine 『DataGrid: Tailor Your DataGrid Apps Using Table Style and Custom Column Style Objects』 Kristy Saunders 著、2003年8月
  7. MSDNライブラリ 『Styling with the DataGridColumnStyle, Part 2』 Chris Sano 著、2005年1月
修正履歴

この記事は参考になりましたか?

特集記事連載記事一覧

もっと読む

この記事の著者

どぼん!(ドボン!)

DOBON.NET内で.NET Frameworkの機能を紹介したWebサイト.NET Tipsやメールマガジン「.NETプログラミング研究」の発行人。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/3 2006/07/11 14:34

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング