「ソフテックだより」では、ソフトウェア開発に関する情報や開発現場における社員の取り組みなどを定期的にお知らせしています。
さまざまなテーマを取り上げていますので、他のソフテックだよりも、ぜひご覧下さい。
ソフテックだより(発行日順)のページへ
ソフテックだより 技術レポート(技術分野別)のページへ
ソフテックだより 現場の声(シーン別)のページへ
私が最近携わったWindowsフォームアプリケーション開発でのお話になりますが、DataGridViewコントロール(表形式でデータの表示、編集を可能とするコントロール)を使用して大量のデータを処理する必要がありました。そのとき先輩社員から頂いたアドバイスでVirtualMode(仮想モード)を使用することになりました。今回のソフテックだよりでは、そのVirtualModeについてご紹介いたします。
VirtualModeはDataGridViewコントロールのモードで、プロパティから設定可能です。(設定方法については、後ほど説明します)
VirtualModeプロパティの説明をVisualStudio上で確認すると、「独自のデータ管理操作をDataGridViewコントロールに対して指定したかどうかを示します。」と表示されます。
この説明だけでは少々わかりにくいですが、「DataGridViewコントロールのVirtualModeプロパティをtrueにすることで、セルに表示するデータを設定する処理と、セルの値が変更された際にデータを格納する処理を自分で実装することができます。」と言い換えることができます。
メリットとして、VirtualModeは大規模なデータを使用するためにデザインされており、大量のデータの取り扱いにおいて、高速かつメモリ使用量の少ないコンパクトな処理にすることができます。
デメリットとして、セルに表示する値の設定や、セルへの入力値の処理などを自分で作成する必要があります。
以下の簡単なデータ(Data1〜5)を20万行表示するWindowsフォームアプリケーション(開発言語C#)において、VirtualModeを使用したDataGridViewコントロールと、使用していないもので、それぞれ表示にかかる時間と使用メモリを比較してみました。
計測環境とデータは以下の通りです。
上記例では、VirtualModeで実装することで高速かつ省メモリで動作するようになったことが分かります。
以下に開発言語C#でDataGridViewコントロールにVirtualModeを実装する方法について、簡単に説明します。
(1)プロパティを設定
VirtualModeはDataGridViewコントロールのVirtualModeプロパティをtrueに設定することで有効化します。
(2) 必要なイベントの実装
VirtualModeを有効にする場合、いくつかのイベントを適切に実装する必要があります。
実装例
以下に比較に使用したアプリケーションの例を示します。この例では、1行分のデータを持つ簡単なクラスのリスト(DataList)から値を表示し、ユーザーによる行の追加や削除を考慮していません。
private void VirtualModeDataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
if(e.RowIndex > DataList.Count - 1)
{
return;
}
switch(e.ColumnIndex)
{
case 0:
e.Value = DataList[e.RowIndex].Data1;
break;
case 1:
e.Value = DataList[e.RowIndex].Data2;
break;
case 2:
e.Value = DataList[e.RowIndex].Data3;
break;
case 3:
e.Value = DataList[e.RowIndex].Data4;
break;
case 4:
e.Value = DataList[e.RowIndex].Data5;
break;
default:
e.Value = null;
break;
}
}
実装例
以下に比較に使用したアプリケーションの例を示します。この例では、1行分のデータを持つ簡単なクラスのリスト(DataList)の値を変更しています。CellValueNeededイベントハンドラと同様に、ユーザーによる行の追加や削除を考慮していません。
private void VirtualModeDataGridView_CellValuePushed(object sender, DataGridViewCellValueEventArgs e)
{
switch (e.ColumnIndex)
{
case 0:
int nVal;
if (int.TryParse(e.Value.ToString(),out nVal))
{
DataList[e.RowIndex].Data1 = nVal;
}
break;
case 1:
DataList[e.RowIndex].Data2 = e.Value.ToString();
break;
case 2:
DataList[e.RowIndex].Data3 = e.Value.ToString();
break;
case 3:
DateTime DateVal;
if (DateTime.TryParse(e.Value.ToString(), out DateVal))
{
DataList[e.RowIndex].Data4 = DateVal;
}
break;
case 4:
Byte bVal;
if (Byte.TryParse(e.Value.ToString(), out bVal))
{
DataList[e.RowIndex].Data5 = bVal;
}
break;
default:
break;
}
}
注意点として、ユーザーが新しい行に移動するたび発生するため、このイベントでDataGridViewコントロールに表示しているデータのListに新しい行用のデータをAddすると、ユーザーが新しい行に移動⇒編集せずにほかの行に移動などの操作をした場合に余計なデータを追加してしまいます。
そのため、ユーザーに行の追加を許可する場合は、編集中の行のデータを全体のデータと別に持ち、RowValidatedイベントで編集を反映するタイミングで編集を反映、追加するなどの工夫が必要です。
これについては、Microsoftから公開されている、VirtualMode実装のチュートリアル(※1)で紹介されています。
今回のソフテックだよりでは、DataGridViewコントロールのVirtualMode(仮想モード)について簡単にご紹介させていただきました。VirtualModeを使用することによって実装が必要なイベントは増えますが、高速化や省メモリといったメリットがあることを理解いただけたと思います。DataGridViewコントロールで大量のデータを表示する必要がある場合には選択肢となるかと思います。
今回ご紹介させていただいた内容が、皆様のWindowsフォームアプリケーション開発の手助けになれば幸いです。
(A.F.)
関連ページへのリンク
関連するソフテックだより