- PR -

DataGridView(バインド)の追加行のCell値をPGから設定した時、DataGridViewに行を追加する方法

1
投稿者投稿内容
@TK
常連さん
会議室デビュー日: 2004/11/10
投稿数: 39
投稿日時: 2007-08-24 11:45
いつもお世話になっております。
くどいタイトル申し訳ありません。

先日「DataGridViewのNotifyCurrentCellDirty()と、RowHeaderに表示されるペンマーク(?)について」というタイトルでスレッドを立たせていただきました。
解決かと思いきや、別の壁にぶち当たってしまったためタイトル・文章を変更し再度別スレッドとして投稿させていただきました。


・用語
本スレッド内では用語を下記のように使わせていただきます
「追加行」
DataGridView.AllowUserToAddRowsプロパティをTrueにした時に表示される一番下の行の事。
「行」
追加行ではないデータ行の事。


・環境
VS2005
C#
Win


・要件
1.
データバインドされたDataGridViewのCellDoubleClickイベント内で、ダブルクリックされたCellの値を更新する必要がある。
2.
DataGridViewの追加行にて「1.」の処理が行われた際には、新規の行として追加される必要がある。
3.
DataGridViewのDataSource(DataTable)は、任意のタイミングで各RowのRowStateから、追加された行(Added)なのか編集された行(Modified)なのか等を判断できる必要がある。


・やりたい事
DataGridViewの特定Cellをダブルクリックすると別ダイアログが開く。
そのダイアログで選択されたアイテム(文字列だったり数値だったり)をDataGridViewのダブルクリックされたCellに表示する。
最後に「更新」ボタンをクリックすると、更新・追加された行だけDBにUpdate・Insertする。


・問題
前回投稿時には下記コードで問題解決したかと思いましたが。。。
(隣の古柴様、まるく様お世話になりました)

コード:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)

{
 if (e.ColumnIndex == column1.Index)
 {
  if (e.RowIndex == dataGridView1.NewRowIndex)
  {
   DataTable dt = (DataTable)dataGridView1.DataSource;
   dt.AcceptChanges();
  }
  dataGridView1[e.ColumnIndex, e.RowIndex].Value = "hoge";
 }
}



下記のような問題が発生してしまいました。

DataGridViewに行が存在しない時に要件「2.」が満たせない。
DataGridViewにあらかじめ行が1行でも存在していれば、追加行でダブルクリックした時に当該Cellが"hoge"になり、新規の行として追加されます。
しかしDataGridViewに行が1行も存在しない場合、追加行の当該Cellが"hoge"に変わるだけで、新規の行として追加されないことに気付きました。

AcceptChanges()を使うため要件「3.」が満たせない
AcceptChanges()を実行した時点で、DataSource(DataTable)各RowのRowStateは全てUnchangedになってしまうため、追加された行や編集された行が判別できない。



上記問題の解決方法を現在調査中です。
判明したことなどあれば随時投稿していきます。

要件を満たせる方法や代替案等ございましたらご教示いただけたら幸いです。
長文失礼しました。
以上、よろしくお願いします。


[ メッセージ編集済み 編集者: @TK 編集日時 2007-08-24 11:52 ]
@TK
常連さん
会議室デビュー日: 2004/11/10
投稿数: 39
投稿日時: 2007-08-24 13:20
自己レスです。

関係あるか分かりませんが気になる動作を報告いたします。
他スレッド等でも既出かと思います。

コード:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
 dataGridView1[e.ColumnIndex, e.RowIndex].Value = "hoge";
}



上記、PGからDataGridViewのCell値を更新するもっとも基本的な形かと思います。

これで追加行をダブルクリックすると、当該Cellは"hoge"となりますが行は追加されません。
つまり追加行のダブルクリックしたCellが"hoge"になるだけです。

その状態で他の行のCellにフォーカスを移動すると、追加行に入力された"hoge"が消えます。
しかし追加行にフォーカスを戻すと"hoge"は表示されます。
(編集中のまま値は保持されている?)

さらにこの状態から、どれでもいいのでカラムヘッダーをクリックします。
すると、"hoge"と入力された行が新規の行として追加されます。
(編集が決定された?)


この動きから、DataGridView(もしくはDataSourceのDataTable)に「Cellの編集が確定されたよ」という通知(?)を行うためのインターフェースが用意されているのでは、と考えています。
その通知を期に追加行への入力が新規の行として追加されるのでないかと思うのですが。
(EndEdit()は効果ありませんでした)


もう少し調査が必要そうです。
以上です。
KI
大ベテラン
会議室デビュー日: 2007/01/10
投稿数: 239
投稿日時: 2007-08-24 15:58
検証がないためできないのですが、記憶を頼りに書いてみます。
この場合の行の追加は CurrencyManager.AddNew メソッドで可能なはずですので、
追加行の場合のみ、Value設定前にこれを呼ぶようにしてみてはどうでしょうか?
@TK
常連さん
会議室デビュー日: 2004/11/10
投稿数: 39
投稿日時: 2007-08-24 16:41
KI様

お返事、ありがとうございます。
ご教示いただいたCurrencyManagerを使った下記コードを実行してみました。


コード:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
 if (e.ColumnIndex == 1)
  {
   if (e.RowIndex == dataGridView1.NewRowIndex)
    {
     DataTable dt = (DataTable)dataGridView1.DataSource;
      CurrencyManager cm = (CurrencyManager)BindingContext[dt];
      cm.AddNew();	// A
    }
    dataGridView1[e.ColumnIndex, e.RowIndex].Value = "hoge";
  }
}




すると、追加行をダブルクリックしたときに2行追加されてしまうという現象がおきました。

DataGridViewに3行(追加行込)存在しているとします。
追加行をダブルクリックすると2行追加されて全部で下記のような5行(追加行込)になります。
1行目:はじめからある行
2行目:はじめからある行
3行目:追加されたhogeの行
4行目:追加された空の行
5行目:追加行

下記コードでもまったく同じ現象を確認しております。


コード:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
 if (e.ColumnIndex == 1)
  {
   if (e.RowIndex == dataGridView1.NewRowIndex)
    {
     DataTable dt = (DataTable)dataGridView1.DataSource;
    DataRow dr = dt.NewRow(); 
    dt.Rows.Add(dr); // A
    }
    dataGridView1[e.ColumnIndex, e.RowIndex].Value = "hoge";
  }
}




両ソースとも、Aの行が実行される直前までは

DataGridViewのRowは3行
DataSource(DataTable)のRowは2行

となっておりますが、Aの行が実行されると

DataGridViewのRowは5行
DataSource(DataTable)のRowは3行

となってしまいます。


もう少し検証してみます。
KI様、他に思い出されたことがありましたらご投稿いただけたら幸いです。

以上、またよろしくお願いします。
@TK
常連さん
会議室デビュー日: 2004/11/10
投稿数: 39
投稿日時: 2007-08-24 16:55
自己レスです。
(自己レス率が高くて申し訳ない)

代替案が見つかりましたのでご報告いたします。

下記サイトを参考にさせていただきました。

http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=1041660&SiteID=7
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=37791&forum=7

私はDataTableを直接DataSourceにバインドしていたのですが、BindingSourceを中継してバインドするようにしました。
そしてCellDoubleClickイベント内は下記のようなコードにします。

コード:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
  if (e.ColumnIndex == 1)
  {
   BindingSource bs = (BindingSource)dataGridView1.DataSource;
    ((DataRowView)bs.Current).Row[e.ColumnIndex] = "hoge";
    bs.EndEdit();
  }
}



このようにすれば要件が満たされることを確認しております。
とりあえず、代替案が見つかったのでホッとしております。


DataTableを直接バインドした場合の方法も是非知りたいものです。
引き続き調査を進めてみようと思います。情報提供いただけたら幸いです。

以上、お願い致します。


KI
大ベテラン
会議室デビュー日: 2007/01/10
投稿数: 239
投稿日時: 2007-08-24 17:22
ごめんなさい、はずしてましたね。
引用:

@TKさんの書き込み (2007-08-24 16:55) より:

DataTableを直接バインドした場合の方法も是非知りたいものです。
引き続き調査を進めてみようと思います。情報提供いただけたら幸いです。


BindingSource.EndEdit でいけるのなら、
BindingSource を介していない場合は CurrencyManager.EndCurrentEdit でいけるかも知れません。
検証できなくて申し訳ないですが…
@TK
常連さん
会議室デビュー日: 2004/11/10
投稿数: 39
投稿日時: 2007-08-24 18:12
KI様

さっそくのお返事をありがとうございます。
代替案が見つかった安心で、一息ついてしまっておりました。


> 検証できなくて申し訳ないですが…

とんでもありません。
お陰様でDataTableを直接バインドした場合と、BindingSourceを介してバインドした場合の二通りの方法を確認することができました。
下記にまとめさせていただきます。


DataTableを直接バインドした場合は、下記のようにしてCellに値を挿入すればよい。
コード:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
 if (e.ColumnIndex == 1)
 {
  if (e.RowIndex == dataGridView1.NewRowIndex)
   {
   // 追加行がダブルクリックされた時の処理
    DataTable dt = (DataTable)dataGridView1.DataSource;
     CurrencyManager cm = (CurrencyManager)BindingContext[dt];
     cm.EndCurrentEdit();
   }
   dataGridView1[e.ColumnIndex, e.RowIndex].Value = "hoge";
 }
}




BindingSourceを介してバインドした場合は、下記のようにしてCellに値を挿入すればよい。
コード:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
  if (e.ColumnIndex == 1)
  {
   BindingSource bs = (BindingSource)dataGridView1.DataSource;
    ((DataRowView)bs.Current).Row[e.ColumnIndex] = "hoge";
    bs.EndEdit();
  }
}




ご協力いただきましてありがとうございました。
本スレッドが他の方の参考になれば幸いです。

1

スキルアップ/キャリアアップ(JOB@IT)