Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
佐藤 美菜
SQL Developer Support Engineer
みなさん、こんにちは。今回は、DataGridView に DataTable をバインドしているときに DataGridView 内のデータを編集した際の動作について、少々注意が必要な場合をご紹介します。
現象
以下のような操作をします。
- DataGridView に DataTable をバインドして画面表示をしている
- DataGridView の値を変更する
- DataTable(DataSet) へ操作を行う ( 例えば、DataTable.Select、DataTable.Compute、DataTable.Copy 等)
この場合、DataGridView で変更した値は、明示的にカレント行を移動しないと DataTable には反映されません。
これは DataGridView の想定された動作です。
詳細
例えば、下記のように「全選択」ボタンで DataGridView のすべての行の col1 をチェックします。そして、チェックされた行数を DataTable.Compute メソッドでカウントします。すると、3 行選択されているにも関わらず、2 行しかカウントされません。
確認コード例(VB)
Public Class Form1 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load ‘ データソースから取得した値の DataTable を DataGridView へバインドします Me.TableAdapter1.Fill(Me.DataSet1.Table_1) DataGridView1.DataSource = Me.DataSet1.Table_1 End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click For i As Integer = 0 To DataGridView1.RowCount - 1 DataGridView1.Item("Col1DataGridViewCheckBoxColumn", i).Value = 1 Next MessageBox.Show("選択数:" & DataSet1.Table_1.Compute("COUNT(col1)", "col1<>0") & "行選択されました。") End Sub End Class |
DataGridView の値を更新すると、カレント行を移動するまでその更新は保留のままになります。今回のように、DataGridView への更新が GUI からではなく、プログラム中から行われた場合はカレント行が移動されません。上記の例では、カレント行である DATA1 の行が保留のままになっています。変更が確定されていないため、DataTable からは意図した結果が得られない状況になります。
DataGridView のカレント行を移動すれば、保留だった行の変更が確定され、DataTable からも結果が確認できるようになるのですが、今回のようにプログラム中から更新する場合には少し対策が必要です。
対策
対策としては、以下の 3 つの方法が考えられます。
- DataGridView の値を更新後、明示的に DataRow.EndEdit を実行する
- DataGridView の値を更新後、明示的に DataTable.AcceptChanges ( または DataSet.AcceptChanges ) を実行する
- DataGridView の値を更新する代わりに直接 DataRow を更新する
対策1: DataRow.EndEdit
DataRow.EndEdit をカレント行に対して行うことにより、この行で行われている変更を終了し確定します。
上記コードでの対策例
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click For i As Integer = 0 To DataGridView1.RowCount - 1 DataGridView1.Item("Col1DataGridViewCheckBoxColumn", i).Value = 1 Next '対処策1 Me.DataSet1.Table_1.Rows(DataGridView1.CurrentCell.RowIndex).EndEdit() MessageBox.Show("選択数:" & DataSet1.Table_1.Compute("COUNT(col1)", "col1<>0") & "行選択されました。") End Sub |
対策2: DataTable.AcceptChanges
AcceptChanges を実行すると、カレント行を含めた、前回 AcceptChanges を呼び出した以降に行われた DataTable への変更を確定します。 このとき DataRowState も変更され、すべての Added および Modified 行は、Unchanged に変更され、Deleted 行は削除されます。
※ DataTable 全体に対して変更が確定され、RowState が Unchanged に変更される点が「対策1 : DataRow.EndEdit」 と異なる点です。
上記コードでの対策例
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click For i As Integer = 0 To DataGridView1.RowCount - 1 DataGridView1.Item("Col1DataGridViewCheckBoxColumn", i).Value = 1 Next '対処策2 Me.DataSet1.Table_1.AcceptChanges() MessageBox.Show("選択数:" & DataSet1.Table_1.Compute("COUNT(col1)", "col1<>0") & "行選択されました。") End Sub |
対策3: DataRow を直接更新する
DataGridView の値を更新する代わりに直接 DataRow を更新すると、DataGridView で表示される値と DataTable の値との間で差が出ないため、意図した結果を得られます。
上記コードでの対策例
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click '対策3 'For i As Integer = 0 To DataGridView1.RowCount - 1 ' DataGridView1.Item("Col1DataGridViewCheckBoxColumn", i).Value = 1 'Next For i As Integer = 0 To Me.DataSet1.Table_1.Rows.Count - 1 Me.DataSet1.Table_1.Rows(i)(0) = 1 Next MessageBox.Show("選択数:" & DataSet1.Table_1.Compute("COUNT(col1)", "col1<>0") & "行選択されました。") End Sub |
どの対策を採用するかは、アプリケーションの要件に依存しますので、要件にあった方法をご選択ください。
<参考情報>
DataRowView クラス
https://msdn.microsoft.com/ja-jp/library/system.data.datarowview.aspx
DataRow.EndEdit メソッド
https://msdn.microsoft.com/ja-jp/library/system.data.datarow.endedit.aspx
DataTable.AcceptChanges メソッド
https://msdn.microsoft.com/ja-jp/library/system.data.datatable.acceptchanges.aspx
DataRowState 列挙体
https://msdn.microsoft.com/ja-jp/library/system.data.datarowstate.aspx