none
vb.net DataGridViewとSplitContainer間でのe.cancelの動きについて RRS feed

  • 質問

  • VisualStudio2019 vb.netでの開発を行っております。

    SplitContainer上のテキストボックスで入力チェックを行い、次にDataGridViewのカンレントでない行をクリックした場合に、テキストボックスにとどまらず、DataGridViewのイベントが実行されてしまいます。ご教授お願いいたします。

    エラー入力後、次にDataGridViewのカンレント行をクリックした場合は、正常動作いたします。

    <実行apの状態>

    新規フォーム上にDataGridViewとSplitContainer及びSplitContainerのパネル1にテキストボックスを1つ、合計3個のコントロールを配置しております。

    フォームのロード上でDataGridViewに2行のデータを作成し、テキストボックスのValidatingでエラーチェエクを行いエラーだった場合に、e.cancel=TRUEの命令を記載しております。

       Private Sub TextBox1_Validating(sender As Object, e As CancelEventArgs) Handles TextBox1.Validating
            If sender.text = "errortest" Then
                e.Cancel = True
                Exit Sub
            End If
        End Sub

    2021年4月1日 6:48

回答

  • DataGridViewはセルの選択をキーボードフォーカスと関係なしに行っているので、外部のフォーカス移動が絡むValidatingと相性が悪いのかも。

    Public Class Form1
    
        Private WithEvents textBox1 As TextBox
        Private WithEvents textBox2 As TextBox
        Private WithEvents dataGridView1 As DataGridView
    
        Sub New()
            textBox1 = New TextBox()
            textBox1.Text = "errortest"
    
            textBox2 = New TextBox()
            textBox2.Top = textBox1.Height + 5
    
            dataGridView1 = New DataGridView()
            dataGridView1.Dock = DockStyle.Fill
            dataGridView1.Columns.Add(New DataGridViewTextBoxColumn() With {.HeaderText = "列1"})
            dataGridView1.Columns.Add(New DataGridViewTextBoxColumn() With {.HeaderText = "列2"})
            dataGridView1.Columns.Add(New DataGridViewTextBoxColumn() With {.HeaderText = "列3"})
    
            Dim sp As New SplitContainer
            sp.Dock = DockStyle.Fill
            Me.Controls.Add(sp)
            sp.Panel1.Controls.Add(textBox1)
            sp.Panel1.Controls.Add(textBox2)
            sp.Panel2.Controls.Add(dataGridView1)
        End Sub
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
            dataGridView1.Rows.Add()
            dataGridView1.Rows.Add()
    
            Me.textBox1.Focus()
        End Sub
    
        Private Sub textBox1_Validating(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles textBox1.Validating
            If DirectCast(sender, TextBox).Text = "errortest" Then
                e.Cancel = True
                Exit Sub
            End If
        End Sub
    
        Private isValiateChecking As Boolean 'dataGridViewで多重にCellValidatingが発生するのをスキップするためのフラグ
    
        Private Sub dataGridView1_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs) Handles dataGridView1.CellValidating
            If isValiateChecking Then
                Return '検証が多重に発生した場合にスキップ
            End If
    
            Dim dgv = DirectCast(sender, DataGridView)
            If Not dgv.Focused Then
                'DataGridViewにフォーカスがない状態でカレントセルが変更されそうになっている場合
    
                isValiateChecking = True
                If Not Me.ValidateChildren() Then 'フォーム内のフォーカスがあるコントロールで検証を実行させる
                    e.Cancel = True '検証が通らないならセル移動はさせない
                End If
                isValiateChecking = False
            End If
        End Sub
    
    End Class

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2021年4月1日 10:34

すべての返信

  • DataGridViewはセルの選択をキーボードフォーカスと関係なしに行っているので、外部のフォーカス移動が絡むValidatingと相性が悪いのかも。

    Public Class Form1
    
        Private WithEvents textBox1 As TextBox
        Private WithEvents textBox2 As TextBox
        Private WithEvents dataGridView1 As DataGridView
    
        Sub New()
            textBox1 = New TextBox()
            textBox1.Text = "errortest"
    
            textBox2 = New TextBox()
            textBox2.Top = textBox1.Height + 5
    
            dataGridView1 = New DataGridView()
            dataGridView1.Dock = DockStyle.Fill
            dataGridView1.Columns.Add(New DataGridViewTextBoxColumn() With {.HeaderText = "列1"})
            dataGridView1.Columns.Add(New DataGridViewTextBoxColumn() With {.HeaderText = "列2"})
            dataGridView1.Columns.Add(New DataGridViewTextBoxColumn() With {.HeaderText = "列3"})
    
            Dim sp As New SplitContainer
            sp.Dock = DockStyle.Fill
            Me.Controls.Add(sp)
            sp.Panel1.Controls.Add(textBox1)
            sp.Panel1.Controls.Add(textBox2)
            sp.Panel2.Controls.Add(dataGridView1)
        End Sub
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
            dataGridView1.Rows.Add()
            dataGridView1.Rows.Add()
    
            Me.textBox1.Focus()
        End Sub
    
        Private Sub textBox1_Validating(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles textBox1.Validating
            If DirectCast(sender, TextBox).Text = "errortest" Then
                e.Cancel = True
                Exit Sub
            End If
        End Sub
    
        Private isValiateChecking As Boolean 'dataGridViewで多重にCellValidatingが発生するのをスキップするためのフラグ
    
        Private Sub dataGridView1_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs) Handles dataGridView1.CellValidating
            If isValiateChecking Then
                Return '検証が多重に発生した場合にスキップ
            End If
    
            Dim dgv = DirectCast(sender, DataGridView)
            If Not dgv.Focused Then
                'DataGridViewにフォーカスがない状態でカレントセルが変更されそうになっている場合
    
                isValiateChecking = True
                If Not Me.ValidateChildren() Then 'フォーム内のフォーカスがあるコントロールで検証を実行させる
                    e.Cancel = True '検証が通らないならセル移動はさせない
                End If
                isValiateChecking = False
            End If
        End Sub
    
    End Class

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2021年4月1日 10:34
  • 先ず、早速のご返信ありがとうございます。

    ご提示いただいたコードにて確認いたしました。

    ご質問させていただいた、一先ず、エラー時(e.cancel=true)、先に進まなくなりました。

    ありがとうございます。

    主要イベントの発生をデバックしたところ下記のようなりました。

    なんとか、(2)状態にとは思いますが、(1)でもdataGridView1_RowEnterを実行させない手段等、ご教授いただければありがたいです。

    (1)操作はご提示いただいたコードを実行、DataGridViewのカンレントでない行をクリックし、実行停止。

    ①textBox1_Enter 
    ②textBox1_Validating start
    ③textBox1_Validating error発生
    ④textBox1_Enter 
    ⑤dataGridView1_CellValidating
    ⑥textBox1_Validating start
    ⑦textBox1_Validating error発生
    ⑧dataGridView1_CellValidating
    ⑨dataGridView1_RowEnter 

    (2)DataGridViewのカンレント行をクリックし、実行停止。

    ①textBox1_Enter 
    ②textBox1_Validating start
    ③textBox1_Validating error発生
    ④textBox1_Enter 


    2021年4月1日 13:07