2008年11月26日水曜日

[.NET]バインドされたDataGridViewに追加した項目を選択状態にする

先ほどの記事でDataGridViewとBindingSourceおよびDataTableの関係について書いたが、それを調べるための目的は、DataGridViewにバインドされたDataTableにプログラムで行を追加したときにその項目を選択させるためだったので、その方法を書いてみることにする。

実際にこのような動作をするプログラムを書かないと、状況がつかめないかもしれないが、DataGridViewは、バインドされたDataTableに新しく行を追加しても、選択位置は一番最初のままである。そのため、新しく追加された項目は、スクロールアウトされていると表示されない。しかも、DataGridViewは選択されている項目を表示させようとするため、さらに行が追加されると、選択されている行がスクロールアウトされていても選択行を表示させるためスクロールする。

すなわち、新しい行を表示させるためにはDataGridViewの選択行を変更しなければならない。ここで前提としては、DataGridViewの選択モードは、FullRowSelectになっているものとする。CellSelectでもうまくいくと思われるが試してはいない。

以下のコードはC++で書くことにするが、VC++2008 Express EditionでDataTableやDataSetをデータデザイナを使って定義する方法は、こちらの記事を参照されたい。

まず、データデザイナで定義をするとヘッダファイルにDataSetのサブクラスが作られて、その中にDataTableのサブクラスを定義するようなコードを生成するが、ここでは、"MyDataSet"や"MyDataTable"のように"My"+クラス名というものを定義したとする。

あと、DataTableの定義の前提として、主キーでAutoIncrementされる列(Column)を定義し、カラム名は"ID"とする。あと、定義されたDataSet(すなわち"MyDataSet")は、Formのメンバー変数として、「MyDataSet^ myDataSet;」と定義され、コンストラクタのどこかで、「myDataSet = gcnew MyDataSet();」のようにインスタンスを生成しており、また、フォームデザイナでは、BindingSourceを"myBindingSource"と定義したとする。

とりあえず、コードは以下の通り

//新しい行を生成する
MyDataSet::MyDataTableRow^ newRow = myDataSet->MyDataTable->NewMyDataTableRow();

//ここでnewRowのメンバー(カラム)にデータを代入する
//newRow-><カラム名> = …;
//カラム"ID"は追加時に設定されるので何もしなくてよい

//行をDataTableに追加する
myDataSet->MyDataTable->Rows->Add(newRow);
myDataSet->MyDataTable->AcceptChanges();

//追加した行のBindingSourceの位置を取得する
int position = myBindingSource->Find(L"ID", newRow->ID);

//BindingSourceの現在の位置を変更する
myBindingSource->Position = position;

ここでの最大のポイントは、BindingSourceの現在の位置はDataGridViewの選択行に一致するのだが、項目がソートされているとDataTableの行(Row)のインデックスとは一致しない。そのため、新しく追加した項目がBindingSourceでどの位置にあるかを調べてから設定するということである。

あと、このコードでの"newRow"はAdd();で"MyDataTable"に追加すると、"ID"にAutoIncrementされた値が代入される。そのため、この値を使って"myBindingSource"のFind();を呼び出せば、位置がわかるということになる。

0 件のコメント: