2015年3月26日木曜日

VB 型付データセット と DataGridView の落とし穴 (VB2008SP1) 続編

さて、前回、DataBase と DataSet と DataGridView について、ぐたぐたと書きましたが、 尻切れトンボ でしたね。
補完しておきます。  えっと、 テーマは、 DataGridView で表示編集する 数値型データ。
DataGridView で、数字の桁数で 調整出来る場合は、前回 も参照して下さい。
今回は、 既定の範囲を超える値のエラー と 文字から数字のエラー と 一意制約違反 を捉えます。


先ず、前提条件。

DataBase で、主キー に設定した列に対して、  DataBase: MyDatabase ColumnName: ID Type: INT32
自動生成で 型付データセット を作り、      DataSet: MyDatabaseDataSet
更に DataGridView に表示します。         DataGridView: TestDataGridView


INT32 ですから、値の範囲は -2147483648 ~ 2147483647 。
主キー制約ですから、値の重複 は不可。
数値型ですから、勿論、アルファベットや文字 は不可。  数字だけ。


この条件下で、標準的に用意される DataGridView は、
該当 Column ( Cell ) に、 文字でも、数字でも、えらく長い数字(例:20桁)でも、入ります。
勿論、列や行を移動すれば、 本来、不正な値ですから、 エラー! と弾かれてしまいますね。

大元の DataBase の構造を反映している証拠なのですが、
出来れば、入力・編集している  Column ( Cell ) の中で、 エラーを潰したいですよね。


では、コードですが、

   Private Sub TestDataGridView_CellValidating(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValidatingEventArgs) Handles TestDataGridView.CellValidating

        If Not TestDataGridView.IsCurrentCellDirty Then
            Exit Sub
        End If

        'test
        Dim headerText As String = Me.TestDataGridView.Columns(e.ColumnIndex).HeaderText
        If headerText = "ID" Then
            Const escapeMsg As String = " [Esc]:Cancel"
            Try
                Integer.Parse(CType(Me.TestDataGridView.EditingControl, TextBox).Text)

            Catch ex As System.ArgumentNullException
                Me.TestDataGridView.Rows(e.RowIndex).ErrorText = "Null" & " (INT32) " & CType(Me.TestDataGridView.EditingControl, TextBox).Text & escapeMsg
                CType(Me.TestDataGridView.EditingControl, TextBox).ForeColor = Color.Crimson
                e.Cancel = True
            Catch ex As System.FormatException
                Me.TestDataGridView.Rows(e.RowIndex).ErrorText = "NotCorrect" & " (INT32) " & CType(Me.TestDataGridView.EditingControl, TextBox).Text & escapeMsg
                CType(Me.TestDataGridView.EditingControl, TextBox).ForeColor = Color.Crimson
                e.Cancel = True
            Catch ex As System.StackOverflowException
                'Me.TestDataGridView.Rows(e.RowIndex).ErrorText = "OverFlow" & " (INT32) " & CType(Me.TestDataGridView.EditingControl, TextBox).Text
                CType(Me.TestDataGridView.EditingControl, TextBox).ForeColor = Color.Crimson
                e.Cancel = True
            Catch ex As System.OverflowException
                Me.TestDataGridView.Rows(e.RowIndex).ErrorText = "OverFlow" & " (INT32) " & CType(Me.TestDataGridView.EditingControl, TextBox).Text & escapeMsg
                CType(Me.TestDataGridView.EditingControl, TextBox).ForeColor = Color.Crimson
                e.Cancel = True

            End Try

            ' for Commit Error Catching
            Me.TestBindingSource.EndEdit()
        End If

    End Sub

    Private Sub TestDataGridView_CellValidated(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles TestDataGridView.CellValidated
        Me.TestDataGridView.Rows(e.RowIndex).ErrorText = String.Empty

    End Sub

    Private Sub TestDataGridView_DataError(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewDataErrorEventArgs) Handles TestDataGridView.DataError
        Dim headerText As String = Me.TestDataGridView.Columns(e.ColumnIndex).HeaderText

        If (e.Context = DataGridViewDataErrorContexts.Commit) Then
            If headerText = "ID" Then
                Const escapeMsg As String = " [Esc]:Cancel"
                Me.TestDataGridView.Rows(e.RowIndex).ErrorText = "CommitUnique" & " (INT32) " & CType(Me.TestDataGridView.EditingControl, TextBox).Text & escapeMsg
                CType(Me.TestDataGridView.EditingControl, TextBox).ForeColor = Color.Crimson
                e.Cancel = True
            End If
        End If

    End Sub


この様なコードでは如何でしょうか。

エラーメッセージをそのまま流用する場合には、 Const ~ の行は 外に出して ひとつに纏めた方がいいかもです。

また、当然、複数の列 ( Column / Cell ) があるでしょうから、 他の列で、違反を潰しきれていない場合、
DataError イベント ハンドラ が捕捉してしまい、 本来、対処すべき処理が 毀れてしまう可能性も否定出来ません。
ご注意!を。

それから、 それから、 上の例では、一意違反の場合、単に、メッセージを示すのみで、
有効な値が入力される迄、該当列を 抜けれません。
実際には、何か、対応方法を検討すべきでしょう、 ね。



と、ここ迄 書いてきて、 以前、日付型の扱い方について書いた事を思い出しました。
立ち位置が違うので、少し、違う展開ですが、 まぁ、参考にはなるかも です。
一応、 リンクを載せて置きます。  

        VB DataGridView と CellValidating



0 件のコメント:

コメントを投稿