DOBON.NET DOBON.NETプログラミング掲示板過去ログ

DataGridで削除した行があると動作が止まる。

環境/言語:[win xp, .NetFramework 1.1]
分類:[.NET]

お世話になります。よろしくお願いいたします。

データグリッドで、選択された複数の行をリストに格納し、
あとで順に処理していくというプロシージャを書いています。
DataGridは dataTableMain から値を得て表示しているものです。

Dim i As Integer
Dim list As New ArrayList
With grdDataGrid
For i = 0 To dataTableMain.Rows.Count
If .IsSelected(i) = True Then
list.Add(i)
End If
Next
If list.Count > 0 Then
Dim j As Integer
j = MessageBox.Show("選択されたすべての列の内容を処理します。", "確認", MessageBoxButtons.OKCancel)
If j = vbOK Then
For Each i In list
S_Execute(i)
Next
End If
End If
End With

ここで、すでに削除された行があると、「インデックスが配列の境界外です」というエラーメッセージが出て、
If .IsSelected(i) = True Then
のところで動作が止まってしまいます。
どう修正したらよいのでしょうか?
■No7802に返信(Ken-koさんの記事)

> ここで、すでに削除された行があると、「インデックスが配列の
> 境界外です」というエラーメッセージが出て、
> If .IsSelected(i) = True Then
> のところで動作が止まってしまいます。

DataTableに含まれるDataRowのステータスについて調べていくと
わかることかな。
削除した列についても、DataTableはその列を削除したことを
覚えてますので、Rows.Countでは削除した列を含めた数を
返してきます。

DataTableに対してAcceptChangesメソッドを実行してから
すべての行に対しての処理を行うか、それぞれのDataRowの
ステータスもチェックしたうえで処理を行うか、どちらかの
方法で解決できると思います。

#DataSetがDBと関連づいていて、この処理の後にUpdateを
 実行するような場合はAcceptChangesを実行しちゃいけません。
 この理由については、なぜDataRowがステータスを持っているかが
 理解できればわかると思います。
操作の過程で行が削除されることがあるのであれば、その瞬間からDataGridの行インデックス
番号とDataTableのRows行コレクションの行インデックス番号は一致しませんよ。
「小野」さんもおっしゃる通り、
DataTableでは、前回確定時以降に新規挿入された行以外の行の場合は「行削除」されても
行の状態が「削除」になるだけで、行そのものは存在し続けます。
(挿入後に変更の確定をしていない行の削除の場合、ほんとに単純に消えます。)


削除行が対象にならないDataGridと、DataTableの行を一緒にループ処理するとかの場合、
Rows行コレクションを直接使うのではなく、行状態で絞り込んで行配列を選択抽出できる
メソッド(探してくださいね)で削除されてない行だけを抽出してあげないと。

(DataGridはDataTableと連携しづらいですよね・・・。)


ところで、具体的にしたい処理は記述範囲外なので分からないですが、S_Executeメソッドに
番号送ってるってことは、メソッド中でまたDataTableのRowsコレクションに番号アクセス
してるんですか?(S_ExecuteはSQLでも発行してるんですかね?)
だったら行(DataRow)を渡すなりして処理するようにして、1回のループで片付けた方が。
(で、数に依存したループではなくFor Eachに変更した方が。)
まぁ何してるかわからないので何とも言えませんが、なんとなく気になったので。
(余計なお世話かな?)
きいぼーです。

こど。さん 小野@どっとねっとふぁん さん
がかかれていることで判られるかもしれませんが、
ここのTips
DataGridで選択されている行を取得する
http://dobon.net/vb/dotnet/datagrid/selectedrows.html
にそのままの事が載っているようです。


■No7819に返信(こど。さんの記事)
> 操作の過程で行が削除されることがあるのであれば、その瞬間からDataGridの行インデックス
> 番号とDataTableのRows行コレクションの行インデックス番号は一致しませんよ。
> 「小野」さんもおっしゃる通り、
> DataTableでは、前回確定時以降に新規挿入された行以外の行の場合は「行削除」されても
> 行の状態が「削除」になるだけで、行そのものは存在し続けます。
> (挿入後に変更の確定をしていない行の削除の場合、ほんとに単純に消えます。)
>
>
> 削除行が対象にならないDataGridと、DataTableの行を一緒にループ処理するとかの場合、
> Rows行コレクションを直接使うのではなく、行状態で絞り込んで行配列を選択抽出できる
> メソッド(探してくださいね)で削除されてない行だけを抽出してあげないと。
>
> (DataGridはDataTableと連携しづらいですよね・・・。)
>
>
> ところで、具体的にしたい処理は記述範囲外なので分からないですが、S_Executeメソッドに
> 番号送ってるってことは、メソッド中でまたDataTableのRowsコレクションに番号アクセス
> してるんですか?(S_ExecuteはSQLでも発行してるんですかね?)
> だったら行(DataRow)を渡すなりして処理するようにして、1回のループで片付けた方が。
> (で、数に依存したループではなくFor Eachに変更した方が。)
> まぁ何してるかわからないので何とも言えませんが、なんとなく気になったので。
> (余計なお世話かな?)
>
みなさま、どうもありがとうございました。
おかげさまで、無事解決できました。
(やはり、DataTableのRowState情報を取得して、それを基に処理を分岐させました)

単純な解決法以外にもいろいろありがとうございます。
もっとスマートな方法があるのは分かるのですが...。まだプログラミング自体慣れていないので、とりあえず今回はこれで満足しておきます。

この度はどうもありがとうございました。
どうぞまたよろしくお願いいたします。

DOBON.NET | プログラミング道 | プログラミング掲示板