【WPF】DataGridの使い方をサンプルで解説(for Windows Form技術者)

この記事は約11分で読めます。

Windows Form で一覧表の画面を作成する場合、DataGridViewというコントロールを使うのが一般的です。

WPFにおいても、同じ役割を担うコントロールとしてDataGridが用意されているのですが、かなり仕様が違っていてDataGridViewと同じように考えるとうまくいきません。

特にマウスクリックされたセルの行番号・列番号を取得したり、値を設定するといった最も基本的な部分が大きく異なっています。

今回は、一覧表を使ったアプリケーションで最もよく使われるであろう、マウスクリックやカーソルキーによるセル移動におけるDataGridの取り扱いを解説したいと思います。

尚、WindowsForm 技術者を対象としていますので、MVVMではなくイベントハンドラに処理を記述する前提のサンプルになっています。

プロジェクトのダウンロード

Visual Studioのプロジェクトを一式、下記からダウンロードできます。

サンプルプログラムの概要

サンプルプログラムは次の機能を試すように作っています。

  • マウスクリックした時の行と列の番号
  • マウス及びカーソルキーによる行/セル移動における行と列番号
  • 削除キー押下時のカレント行(又はセル)の行と列番号
  • 指定した行/列番号への移動と表示
  • 行選択モード/セル選択モードの繰り替え

また、上記に加えて

  • 行番号の表示
  • 仮想表示モードによる高速化
  • コンテキストメニュー表示
  • コンテキストメニュー表示時DataGridの選択を維持
  • ドラッグ&ドロップへの対応

という機能についても搭載しています。

では、まずサンプルプログラムの動作をご覧ください。

ソースコードについて

XamlとC#のソースコードを掲載しておきます。

まずXamlから。

次はC#のソースコードになります。

要点の解説

まず前提として、サンプルプログラムでは、それぞれの処理をメソッド化しており、イベントハンドラからメソッドを呼ぶような作りにしています。

細かい部分はソースコードを見て頂くとして、ここではメソッドを中心に要点を解説していきたいと思います。

DataTableをDataGridに表示

DataTableをDataGridに表示する方法は次の通りです。

Xaml側

C#ソースコード

DataGridは、ItemSource プロパティに表示したいコレクションをセットすることで表示できます。

ただ、ItemSource にDataTable をセットしようとした場合

  • コレクションに変換するのが面倒
  • DataContextを経由してItemSourceにバインドするのが楽

という理由から、DataContextにDataTableをセットし、Xaml上で ItemSource にバインド(ItemSource = “{Binding}”)して使います。

DataContextはobject 型であるため、DataTableを型変換無しにそのままセット出来ますし、逆に取り出したい時は (DataTable) で型変換するだけで済むので、DataGridVIewのDataSourceプロパティと同じ様に取り扱いできます。

指定した行番号までスクロールして表示

DataGridViewに比べて取り回しが面倒ですが、次のソースコードで指定した行にジャンプし、選択状態にすることが出来ます。

但し、これは SelectedUnit(行選択かセル選択かを示すプロパティ)に行選択モード( FullRow) が設定されている場合のみ有効です。

行番号と列番号で指定されたセルまでスクロールして表示

こちらは、行と列を指定すると、カレントセルの位置までスクロールして選択状態で表示してくれます。

SelectedUnit にセル選択モード( Cell) が設定されている場合のみ有効です。

選択セルの行番号と列番号を取得

選択されている(背景色が青表示)セルの行と列の番号が取得できます。

ただ、未選択状態の場合は、CurrentCellが null になったり、SelectedIndex が -1 にってエラーになりますので、何らかの対策が必要です。

ちなみに、今回のサンプルには入っていますが、どのイベントからも呼び出していないので、興味のある方はサンプルを書き換えて実験してみて下さい。

カレントセルの行番号と列番号の取得

カレントセルの行番号と列番号を取得します。

列ヘッダのクリックや、他のコントロールをクリックするとカレントセルが取得できなくなり、CurrentItem や CurrentCell が null となってしまいます。

その為、null チェックを入れています。

SelectedUnit が Cell、 FullRow のどちらでも正しく行、列の番号が取得できるので、使い勝手は良いです。

マウス及びキーボード操作のいずれかでセルが変更されてた時、何らかの処理を行わせたい場合 CurrentCellChanged のイベントハンドラを使います。

また、削除や挿入などのキー操作の際、対象となる行、列を特定する場合は、PreviewKeyDown を使います。

マウスクリックしたセルの行番号と列番号を取得

マウスクリックしたセルの行と列の番号は次のソースコードで取得できます。

マウスでクリックした座標からセルを特定するので、これを使う場合は PreviewMouseDown イベントハンドラから呼び出してください。

行番号を表示する

単純に、行ヘッダに番号を表示しているだけです。

Googleで検索すると、同じようなソースコートがヒットすると思います。

この方法はあくまでも簡易的なため、たまに表示ズレを起こす事が有ります。

ドラッグ&ドロップの付与

このブログではお馴染みですが、ドラッグ&ドロップをDataGridに付与するソースコードです。

WindowsForm の場合と微妙に異なりますので、WPFの場合はこちらをお使い下さい。

仮想表示モードによる高速化

WindowsForm のDataGridView に比べて、WPFのDataGridの表示速度は非常に遅く、ずいぶんもっさりしています。

これを解決する方法として、仮想表示モードというのがあります。

Xamlで以下の様に記述することで、DataGridViewにかなり近い表示速度になります。

コンテキストメニュー表示

コンテキストメニューは次の様に記述します。

<Menu Item> は入れ子で階層化が可能で、

  • それぞれに名前を付けてイベントハンドラを作る
  • 1つのイベントハンドラの中で、 sender を見て処理を分ける
  • Command を定義して呼び出す

という方法でメニューを実装できます。

コンテキストメニュー表示時DataGridの選択を維持

DataGridで右クリックによるコンテキストメニュー表示時、DataGridの選択状態(セル背景が青色)が解除されたように見えてしまいます。

実際には薄い背景色が表示されているのですが、見た目上選択が解除されたように見えてしまいます。

これを解決するため、右クリック時にも選択中と同じ背景色と文字色になるよう設定しています。

列の右寄せ

列に値される値は、初期状態では全て左寄せになっています。

例えば数値項目だったら右寄せしたり、区分やフラグの項目だったらセンタリングしたい場合があると思います。

DataGridの場合は、次の様に記述することで右寄せやセンタリングが可能です。

Xamlで右寄せやセンタリングする場合、 Property や Value を使いますが、これをC#のコードで行っています。

このメソッドの使い方は次の様になります。

この方法を使えば、

style.Setters.Add(new Setter() {Property = Foreground,Value = Brushes.Green } )

と記述することで、その列の文字色を変える事もできます。

カラム名に使うと値が表示されず、最悪エラーになる文字

DataGird.DataContext に DataTable を代入して、DataGRidにカラムを自動生成させる場合、DataTableのカラム名に特定の文字が含まれていると、エラーになったり値が表示されなくなるといった問題が発生します。

これはカラム名に、XamlにおけるBindingの予約文字が含まれていた場合に発生します。

予約文字は []()./ の6種類(これ以外にもあるかもしれません)で、これらの文字がカラム名に1つでも含まれていると、そのカラムの値はすべて表示されなくなります。

さらに、[] や () は必ず閉じている(対になっている)必要があり、例えば [ や ( が1つだけしか含まれていない場合、その時点でエラーになってしまいます。

回避方法はいくつかありますが、一番簡単なのは全て全角文字に置き換えることです。

もう1つの方法は、カラムが自動生成される際に発生するAutoGeneratingColumn イベントハンドラで、予約文字をエスケープしてしまう方法です。

正し、この方法は[] や () が対になっているなら正しく処理できますが、対になっていない場合はエラーが発生してしまいます。

もう1つの回避方法として、DataTableを作成する際、カラム名には”Column1”,”Column2”など予約文字が含まれない名前を付与しておき、元の名前は Caption に記録しておきます。

そして、AutoGeneratingColumn イベントハンドラ内で、DataGridのカラムが生成される直前に HeaderにCaption を代入してしまうという方法です。

例えば、”住所(” “氏名[/” “年齢” “職業” というカラム名にしたい場合、ColomnNameには Add(“”) メソッドで自動的な連番名を付与しておき、元のカラム名は Caption に登録しておきます。

AutoGeneratingColumnのイベントハンドラでは、 sender からカラム名とDataContextに登録したDataTable(実際はItemSourceからDataViewの形で取り出す)を取得し、PropertyNameに渡された列名(”Column1″など)に該当するCaptionを特定、Headerに代入します。

DataGridの困った仕様ではありますが、以上の方法で回避することが可能です。

カラム名に表示されない文字

DataGridのカラム名にアンダースコア ‘_’ が含まれていた場合、アンダースコアは表示されません。

DataGridがカラム名に含まれるアンダースコアを、アクセスキーとして判断するためです。

これは、アンダースコアを2つ並べることで解決します。

具体的にいうと、Replace(“_”,”__”) としてやることで対応可能です。

[]()./ などの予約文字をカラム名として表示する際、AutoGeneratingColumn イベントハンドラを使うことを先ほど解説しましたが、この部分を次のように書き換えることで解決できます。

まとめ

DataGridは、WindowsFormのDataGridViewと同じ目的のコントロールであり、複数選択、ReadOnly、ユーザー操作による行挿入や削除の禁止など、共通点も多いのですが、カレントセルの行番号、列番号に関する部分は仕様が大きく変わっています。

今回は、DataTableの表示、マウスやカーソル操作におけるセルの行番号、列番号の取得、行番号、列番号による画面スクロールなど、DataGridViewと同じように扱うため、知っておくと便利な点について解説しました。

また、もっさりしていると言われがちな表示速度の改善についても具体的に解説しています。

これでDataGridViewとほぼ同じことが出来るようになると思いますので、WPFへの移行を検討中の方の参考になれば幸いです。

タイトルとURLをコピーしました