2012年9月3日月曜日

DataGridViewヘッダーの拡張に関する問題の解消方法(DataGridViewのヘッダーを使わず、ヘッダーを簡単に自作する)


下記の話が長いので要約すると、、、

業務プログラムでDataGridViewを使う場合、DataGridViewのヘッダーを使わずデータ行・列の上部と左部をヘッダー行ヘッダー列として使う。
そう決めてプログラムを作れば面倒なDataGridViewのヘッダー処理は全て不要になります。
すると開発はスピーディーになりメンテナンスもし易くなります。

DataGridViewのヘッダーは使わない。これで幸せになれるという話です。

ただ見た目はどうでしょう・・人それぞれですからね。






(2013/2/22コード追加)

文字で説明するのもなんなので、サンプルコードをUPしておきます。興味あればご覧ください。
※質問にはお答えしませんので、こちらの超!素晴らしいサイトで調べてください
※この、超!素晴らしいサイトがあるおかげで、先回のPG開発工数は1/3減少しました@@(感謝)

サンプルソリューション→ DataGridHeaderSample.zip

※VS2010で作成しています
※.net framework 4
※WindowsFormアプリ
※サンプル用に改造したので使っていない変数やコードありますが、ご了解を。






ここからはどうでも良い文章になってしまいましたが、残しておきます。


「 前置き 」

と言う事で、また今回もDataGridViewに表示するデータは全て手作りで作ってます。
そしていつも問題になるのが、ヘッダー。
特にDataGridViewになって恐ろしく頭がよくなった感じで、ホント自動でなんでもやってくれます。しかし自分でヘッダーをカスタムしようとすると突然大きな壁に当たりますね。

今回はヘッダーと呼ばれる固定の行列が、初期で8行(常時固定4行)、2列、あります。DataGridViewのヘッダーを拡張して作ろうかと思いnet徘徊してみましたが、あまり現実的でない情報しかなく、しかも.net2.0時代の物ばかり。その辺から既にDataGridViewのヘッダー拡張手法は進化してないよう。

解説を見ると・・・

私の嫌いな、行、列、をドロー中のwindowsから制御分捕って線画しなさいと(大昔の様に自分で画面書け的な)。私はこの手のwindowsドロー系の制御をプログラマが行う事は嫌なのでやったことはありません。
理由は大体昔から相場が決まっていて、罫線が出ないある部分だけ線画されない、そんなMS側ブラックボックスの問題が決まって必ず出るからです。使うと使っただけ馬鹿を見ます。
それにMSのブラックボックス処理はパッチ入らない限り治る可能性はゼロで、第一プログラマ側では内部コードは永遠にコントロール出来ませんから。





「DataGridViewにおけるヘッダーの考え方と作り方」

私のやり方はヘッダーを非表示にし使いません。ヘッダーとは関係ありませんがデータバインドも使いません。データ領域には自分で行や列を作って1行づつADDしながら行を書きカラムを書いて行きます。
そしてここからここまでをヘッダー(固定行)にする。そう決めてその部分だけ色を変えてみると・・・

立派なヘッダーに見えます(笑)

  // ヘッダーの行数・カラム数(0~)
  const int _GridHeaderColumns = 1; // 2カラム
  const int _GridHeaderRows = 4; // 5行

  //行列ヘッダー非表示
  dataGridView1.ColumnHeadersVisible = false;
  dataGridView1.RowHeadersVisible = false;

  // 固定行・固定列(ヘッダー)
  dataGridView1.Columns[_GridHeaderColumns].Frozen = true;
  dataGridView1.Rows[_GridHeaderRows].Frozen = true;

  // 色を付ける
  ・・・
      





「 いちいち一行ずつ自分で行を作るの!?そんなの面倒・・・と言う方に 」

面倒と思われるかも知れませんが、やってみると結構簡単。1行作ってカラムに文字を入れ色を変える。たったそれだけです。
色を変えて固定にしスクロールしても動かないようにすれば誰が見てもヘッダーにしか見えません。そしてその下にDBから読んで自分で加工したデータ行を必要行数分作ってゆくだけ。基本縦loopを使って作表完了。

縦計が必要ならloopで表を作った後に、更にまた1行目からloopさせ合計計算する。1度のloopでなんでもしようとせず、シンプルloopを数回使った方が速度が速くメンテも楽です。

またデータBINDせず自分で行を作っていくなら、あとの処理を考え各行に目印となる数字を入れると楽。私は0~の数字に意味を持たせ(0:ヘッダーカラム名、2:ヘッダーカラムの単位、~5:データ行の△~)データ行は小計を入れるタイミングの行に目印をしたりしています。そしてある行を取得したい場合はloopさせその数字をhitさせれば処理も簡単です。

これは注意点ですが、美しく作り過ぎない事です。最左に数字入れ非表示にする、そういうのを嫌う人がいますがシステムはコストを掛けず楽に動いて楽にメンテ出来る事が一番の目標です。オブジェクト思考信者になる必要は学者でないなら不要です。





「 すると、また疑問に思われる方には・・・ 」

自作コードだと最適化されていないので速度も出ず全行表示されるまでに時間がかかるのでは?そう思われる方もいると思いますが、私的に言うと、遅いのはデータ表現をオブジェクト化し過ぎです。
何でもオブジェクト、そして入れ子、階層化させ1行を表現、そんな作りにしていると全行表示するに数十倍~数千倍の時間かかると思います。いったい1行作るのにオブジェクト幾つ作る必要があるのでしょうか。

WindowsPhoneアプリの開発で、そんな美しいコードで多量のオブジェクトを生成し表を作る高級サンプル引っ張ってきましたが、残念ながら遅すぎて使えませんでした。
このサンプルはオブジェクトが入れ子になっており、あるデータを1行表現するオブジェクトの中に子孫オフジェクトが合計100程。たった100行作るのにその高級サンプルは一万個のオブジェクトを生成していました。

構造もコード的にもとても美しかったのですが、これは残念ながらデータ表現にオブジェクトを使い過ぎた典型的な失敗例です。手時計による実測では、昔ながらのキタナイコードで100行を瞬時に出力するに比べ高級オブジェクトは100行の一覧表示に30秒も必要でした。これはキタナイコードの1,000倍の時間です。厳密に測れば1万倍の時間がかかっていたかも知れません。

PCのパワーでも同じで、最速に作るならなるべくオブジェクト使わない様に大昔の上から流れるようなキタナイコードを書くと速度は速いです。ただメンテが・・・でしょうから、その辺の比率は最大6:4か7:3で、この:4、:3がオブジェクト指向的な作りです。

ただ・・・一歩引いて言うと、開発の規模によると思います、クラスを作る=再利用用途、は。小さな数十人月程のシステムの場合、再利用するにも機能が少なすぎて再利用する場面が少ないことが多く、そんな場合は机上で厳密にクラス設計をするだけ時間の無駄。ぱっと重要な部分のみ大まかにしっかり設計し、その他の部分は各人へ、そういうのが良いかもしれません。
ただ、超!出来る方がベースとなるフレームワークを作るなら話は別ですが。個人的には自作フレームワークを作らないのなら、クラス設計による処理の再利用化?共通化?だけを行っても時間がかかり使いづらくあまり意味がない気がします。
またもったいないからと、あまりにミクロな機能を共通化して回ると、クラスだらけで探すのも大変、、生産性は確実に落ちます。
とにかく、規模ですね、システムの大きさによると思います。でかいシステムはハードに次もむ¥もでかい=処理系の処理能力が高いことが多いですし。



「 再度、結論 」

ヘッダー=DataGridViewで言うヘッダー
そう思ってしまうとこの部分を拡張しないとヘッダーが作れません。すると嵌ったりオブジェクトを使い過ぎるだけです。
そういった場合はDataGridViewのヘッダーを拡張するのではなく、自分の頭を柔らかく拡張した方が賢明です。

データ領域だけどこの部分はヘッダー(固定行)として使う、そう決めればDataGridViewにおけるヘッダー問題は全てが一瞬で解決し、問題はゼロになります。