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

DataGridのセルの値の取得について

環境/言語:[Windows XP/VB.NET/NET Framework 1.1]
分類:[.NET]

2011/02/16(Wed) 23:22:36 編集(投稿者)

こんばんは、初めて投稿させていただきます。

現在VB.NETで開発を行っております。
開発内容として、

@フォームロードにてDataGridに必要な情報を設定し、DataGridの箱を作成。
A検索ボタンを押下し、DBからデータを取得。
B取得した内容をDataGridに表示(入力等の操作は可能)。
CDataGridのセルAを変更されたらセルAの値に紐づく値で、同じ行のセルBの内容を書き換える。
D登録ボタンを押下し、DBに登録・更新を行う。

という単純な内容をフォーム上で実装しています。

何が問題になっているかというと、
Cの処理をLeaveイベントで呼び出し、値の変更後のセルを確認しているのですが、変更前の値が取れてきてしまいます。
ただし、値を変更してから違うセルにフォーカスを移動させ、再度元のセルにフォーカスを移動すると変更後の値が取得出来ます。
例)
セルAを田島⇒山田に変更。このタイミングでは田島が取得出来てしまうが、他のセルにフォーカスを移動し、再度前述のセルAにフォーカスを移動すると山田が取得出来る。
…という様に、一度フォーカスの移動をしないとセルAの値が正しく判定されない。
※TextChanged、LostFocusイベントで実装しても同じ結果です。

今回.NET自体初めて触るので何が問題になっているのか分かりません…。
以下ソースになりますが、ご教授いただけないでしょうか?(不要であろう箇所は割愛しております)
申し訳ありませんが宜しくお願いします。

Friend Class Form1
  
  Private mStyle As DataGridTableStyle
  Private mTable As DataTable
  Private mRow As DataRow
  Private mSet As New DataSet("テーブル")
  
  'フォームロード処理
  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
    '-----------------------------------------------------------------------------------------
    ' データグリッドの初期化
    '-----------------------------------------------------------------------------------------
    mTable = mSet.Tables.Add("テーブル")
    Dim DGTS As New DataGridTableStyle
    DGTS.MappingName = mTable.TableName
    DataGrid1.TableStyles.Add(DGTS)
    
    Dim dc1 As DataColumn = mTable.Columns.Add("項目1", GetType(String))
    Dim dc2 As DataColumn = mTable.Columns.Add("項目2", GetType(String))
    
    Dim style1 As New DataGridTextBoxColumn
    Dim style2 As New DataGridTextBoxColumn
    
    style1.MappingName = dc1.ColumnName
    style2.MappingName = dc2.ColumnName
    
    style1.HeaderText = dc1.ColumnName
    style2.HeaderText = dc2.ColumnName
    
    DGTS.GridColumnStyles.Add(style1)
    DGTS.GridColumnStyles.Add(style2)
    
    DataGrid1.SetDataBinding(mSet, mTable.TableName)
    DataGrid1.CaptionVisible = False
    
    '-----------------------------------------------------------------------------------------
    ' イベントハンドラ追加
    '-----------------------------------------------------------------------------------------
    Dim ts As DataGridTableStyle
    ts = DataGrid1.TableStyles("テーブル")
    
    'DataGridTextBoxColumnの取得
    Dim cs As DataGridTextBoxColumn = CType(ts.GridColumnStyles(1), DataGridTextBoxColumn)
    
    Dim tb As TextBox = cs.TextBox
    AddHandler tb.Leave, AddressOf tb_Leave
  End Sub
  
  '検索ボタン押下処理
  Private Sub cmdSrch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSrch.Click
  
    '-----------------------------------------------------------------------------------------
    ' DB検索処理
    '-----------------------------------------------------------------------------------------
    '〜〜割愛させていただきます〜〜
    
    '-----------------------------------------------------------------------------------------
    ' データグリッドの設定
    '-----------------------------------------------------------------------------------------
    
    '検索する度に行が増えるので、データテーブルをクリア
    mTable.Clear()
    
    For i As Integer = 0 To DBの取得件数 - 1
      
      '取得値の設定
      mRow = mTable.NewRow
      mRow("項目1") = DBのカラム1
      mRow("項目2") = DBのカラム2
      mTable.Rows.Add(mRow)
    Next i
    
    DataGrid1.DataSource = mTable
    DataGrid1.SetDataBinding(mSet, mTable.TableName)
  End Sub
  
  'フォーカス移動時の処理
  Private Sub tb_Leave(ByVal sender As Object, ByVal e As EventArgs)
    
    '-----------------------------------------------------------------------------------------
    ' 値の確認
    '-----------------------------------------------------------------------------------------
    Debug.WriteLine("操作行番号:" & DataGrid1.CurrentRowIndex)       ←正しい値が表示される
    Debug.WriteLine("値:"& DataGrid1(DataGrid1.CurrentRowIndex, 0))    ←変更前の値が表示される
    
    '項目1が山田なら項目2に小川を設定
    if DataGrid1(DataGrid1.CurrentRowIndex, 0) = "山田" then
      
      DataGrid1(DataGrid1.CurrentRowIndex, 1) = "小川"
    End If
  End Sub
End Class
■No28184に返信(山田さんの記事)
> 何が問題になっているかというと、
> (4) の処理をLeaveイベントで呼び出し、値の変更後のセルを確認しているのですが、変更前の値が取れてきてしまいます。

Leave イベントだとタイミング的にまずいでしょう。
Validating イベント以降であれば問題ないと思いますが、
ただこれ、Leave というか CellLeave 系のイベントでないと違和感のある動作になりませんか...?

# それにしても 1.1 だからしょうがないですが DataGrid は久しぶりに見た...
2011/02/17(Thu) 23:16:06 編集(投稿者)

■No28186に返信(じゃんぬねっとさんの記事)
> ■No28184に返信(山田さんの記事)

> # それにしても 1.1 だからしょうがないですが DataGrid は久しぶりに見た...
そうですね、ネットで探してみても大体はDataGridViewを使った内容のものがひっかかってきたり…
他の部分の実装でもDataGridViewが使えればものすごく楽になる箇所があったりでなんだかなぁって感じです。

そして本題ですが、昨日指摘していただいた内容で再度実装し直した所、
少し細工は必要でしたが昨日の時点での期待していた動きにはなった様です。
ありがとうございます。

修正した箇所について
まずCurrentCellChangedイベントを使って試した所、
別の箇所にフォーカスを遷移させると遷移後のセルの値が取れてきてしまったので
TextChangedイベントでセル位置を退避させてから、
CurrentCellChangedイベントを以って遷移前のセルの値を取得・判定するという実装をしました。


  Private Sub tb_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs)

    '-----------------------------------------------------------------------------------------
    ' セル位置の退避
    '-----------------------------------------------------------------------------------------
    mRowNum = DataGrid1.CurrentCell.RowNumber
    mColumnNum = DataGrid1.CurrentCell.ColumnNumber
  End Sub

  Private Sub td_CurrentCellChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGrid1.CurrentCellChanged

    '-----------------------------------------------------------------------------------------
    ' 退避したセル位置のチェック・更新
    '-----------------------------------------------------------------------------------------
    If mColumnNum = 0 Then

      If Trim(DataGrid1(mRowNum, 0)) <> Space(0) And _
       DataGrid1(mRowNum, 0) = "山田" Then

        DataGrid1(mRowNum, 1) = "小川"
      Else

        DataGrid1(mRowNum, 1) = Space(0)
      End If
    End If
    
    '特に見ていない列番号・行番号を設定(他行に移動が出来なくなるため適当な値を設定)
    mRowNum = 0
    mColumnNum = 0
  End Sub


ただ、この実装が問題になっているかはわかりませんが
1.DataGridの画面操作にて自動で追加された行の項目1に山田を入力し、
  更に次の追加行に移動すると、今入力した山田に紐づく小川が項目2に設定されない(一瞬だけ表示される)。
2.1.の操作以降、追加された行には入力した値がうまく設定されなくなる(項目1を入力しても他セルに移動すると入力値が消えてしまう)。
3.上記の状態になってからキーボードの十字キーを連打したりすると「インデックスが配列の境界外です」というエラーが発生する。
という現象が起こる様になりました。
1.の最初の自動追加された行より下のレコードを操作しようとしなければ不具合は起こらないので
追加行で何かしら異常が起こっているのでしょうが、修正するにあたり、行が追加されたというイベントは拾う事は可能なのでしょうか?
■No28204に返信(山田さんの記事)
> 1.の最初の自動追加された行より下のレコードを操作しようとしなければ不具合は起こらないので
> 追加行で何かしら異常が起こっているのでしょうが、修正するにあたり、行が追加されたというイベントは拾う事は可能なのでしょうか?

DataSource を使っているならば、RowState を見ればわかると思います。 それとも、DataGrid の最下部に表示される未確定の新規行 ('*' で表示される行) のお話でしょうか?

現在の実装だと、EditingControl が表示された時の Row と Column を保持しておいて、CurrentCell が変更された時に最初のカラムが操作されていた場合のみ処理を実行していますよね。
これだったら (最初の状態に近いですが) EditingControl が編集を終えた時に実行した方が賢明だと思います 。
とりあえず、今の実装のままなら DataGrid 自体から Leave した時にも処理が必要ではないでしょうか。

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