2009-04-09

.NET Framework の DataGridView  [by miyachi]

現在開発中のプロジェクトはMacOS-Xで動作しているあるアプリをWindowsに移植するというもの。Windows版もC++とMFCなら経験もあるので簡単ですが、せっかくなのでC#と.NET FrameworkだけでGUIも作ってしまおうと初めて本格的にC#だけでアプリを開発しています。これがなかなか一筋縄では行きません(笑) まあでも経験値はアップしていると思うので頑張りどころです。

閑話休題。さて今週取り組んでいたのは以下のようなスマート検索のダイアログです。問題になるのはメインの検索条件を入力する部分です。プルダウンありテキスト入力ありボタンありと言う事で DataGridView クラスを使うことにしました。



これが思った以上に簡単には使えない!何の罰ゲームですか?と言う感じでした。まあ情報はあるんですが私には判りにくかったです。なのでここで簡単にポイントだけ押さえておこうと思います。以後興味がある方は [続きを読む] にて。

まずVisual Studio 2005のデザイン画面で部品を配置します。メインはDataGridViewを置き、列の編集によって必要となるパーツを設定して行きます。今回は順番にItemリスト、Keywordテキスト、Ruleリスト、Addボタン、Delボタンの5列を作成します。この辺りまではGUIを使って作業できるので楽ちんです。リストはGUIでもItemsのコレクションで予め指定しておく事も可能です。この辺りまでは特に問題もないでしょう。

1)同じ列で異なるドロップダウンリストをセットする

今回はItemリストの選択した種類によってRuleリストの内容が2種類あります。そうなると先に書いたItemsのコレクションは列全体に対する指定なので使えません。さてここでハタと困ってしまいました。ではどうすれば列単位では無くセル単位で異なるリストを指定できるんだ?色々ググってみましたがなかなか具体的にどうすれば良いかが理解できません。まあこれは私の能力の問題ですが。ComboBoxのようなリストを使う列はDataGridViewComboBoxColumnクラスでFormから自動生成されています。DataGridViewComboBoxColumn.DataSourceにDataTableクラスで自分で生成したリストは割り付けることができます。セル単位の場合にはDataGridViewComboBoxCell.DataSourceにセットすれば良い事は分かりました。ただどうやってDataGridViewComboBoxCellを得るかが間抜けな事に理解できません。結局セルに関してはベースとなるDataGridViewクラスでDataGridView[columnIndex, rowIndex]により各セルが取得出来ることに気がつき以下のように取得してリストをセットするようにしました。

 DataGridViewComboBoxCell cell =
  (DataGridViewComboBoxCell)GridView[columnIndex, rowIndex];
 cell.Value = myValue;
 cell.DataSource = myTable1;

myTable1がセットしたいリストを持つDataTableです。またcell.Valueで選択項目を指定できます。注意点としてリストを変更した場合にリストの項目数が違うとちゃんとValueを指定しておかないと存在しないindexのリストを表示しようとして例外が発生することがあります。これで何とかセル単位でリストの指定が出来るようになりました。

2)セルのリストが変更したイベントを取得する

セルへのリストの指定が出来るようになったので、本題のItemリストが変更されたらその内容に従ってRuleリストを変更するように実装をします。でイベントを色々チェックしてみますがどうもリスト変更を標準でフックするイベントは無いようです… なんで?とググってこれは簡単に対応方法を発見しました。

 DataGridViewでセルの編集に使われているコンボボックスのSelectedIndexChangedイベントを捕捉する

結局DataGridViewでEditingControlShowingとCellEndEditのイベントを使って自分でSelectedIndexChangedイベントを発生させる必要がありました。う~んこのくらいは標準で用意して欲しいなあ。ちなみにこのノウハウが書いてあるこのページはDataGridViewを使うなら一通り目を通しておいて損は無いです。情報ありがとうございましたm(_ _)m

3)各セル要素を1回クリックしただけでプルダウン表示や入力状態にする

標準のDataGridViewの動作としてComboBoxタイプのプルダウンは3回クリックしないと表示できません。Textタイプでも1回目のクリックで選択状態になり2回目のクリックでやっとカレットが表示された入力状態になります。これは不便と言うことで先のサイトを見るとやはりちゃんと回避方法が書いてありました。

 DataGridViewのコンボボックスのドロップダウンリストが一回のクリックで表示されるようにする

リストの場合は SendKeys.Send("{F4}"); をCellEnterイベントの時に実行すれば良いとのこと。ついでにテキストの場合には SendKeys.Send("{F2}"); とすることで同様に1回のクリックで入力状態に出来ます。とこれを組み込んだところウイルスバスター2009から以下のような警告が出るようになってしまいました。



むう。まあ強制的にキー入力を送りつけているのでウイルス的と言われればそうなのかもしれません。これは回避方法が思いつかなかったのでとりあえずこのままです。

4)DataGridViewのスクロールバーを最初から表示する

これで終わりかと思ってテストをしていると行を追加して行き表示範囲をオーバーした場合には縦スクロールバーが出てしまいボタンが隠されてしまうことに気が付きました。これは最初から縦スクロールバーを出しておけば良いなと思いDataGridViewの公開プロパティやメンバを探します。スクロールバーを常に表示しない状態には出来るけどどうも常に表示するオプションは無いようです…やれやれ。DataGridViewのプロテクトされたメンバとしてVerticalScrollBarがあります。プロテクトされているのでDataGridViewから派生させたMyDataGridViewクラスを作成して対応します。VerticalScrollBar.Visibleをtrueにして見た目が変更されるVerticalScrollBar.VisibleChangedでイベントハンドラを定義してそこでスクロールバーのサイズ調整と最後に VerticalScrollBar.Show(); とすることで常に表示されるようになりました。

※)最後に

以上で今回マスターしたDataGridView関連のノウハウは全てです。どうも痒いところに手が届かないもどかしさを感じたのでした。DataGridView.VerticalScrollBarなんかも最初から公開されたPublicなメンバーだったらクラスの派生もしなくて済むのにとか。他のクラスでもまだまだ仕様が練れていない感じがあります。.NET Frameworkも将来の拡張に期待と言うところでしょうか。そうそうDataGridViewクラスは.NET Framework 2.0からさポートされたクラスですのでご注意下さい。本当はDataGridViewってデータベースのデータを表示したり使う目的がメインのようなので今回のような使い方自体がイリーガルなのかもしれません。
2009-04-09 13:00:53 - miyachi - [プログラミング] -

コメント一覧

コメント無し

コメントを書く

このアイテムは閲覧専用です。コメントの投稿、投票はできません。