none
DataGridViewのコンボボックスで,DropDownListから値を選択した際に,編集中のセルを確定させたい RRS feed

  • 質問

  • 他に同様な質問がなかったため,起票させていただきます。

    内容は,DataGridViewのコンボボックス(comboBox)の動作に関しての質問です。

     

    [目的と内容]

    コンボボックスでDropDownListから値を選択した際に,編集中のセルを確定させたいと思っております。

    そこで,下記のサイトを参考に以下のコーディングを実施しました。

    [実施結果]

    コンボボックスを選択しDropDownListから選択すると,1回目の選択ではコンボボックスに値が入力されませんでした。2回目以降は,値が入力されます。

    [質問]

    ①上記の現象はなぜ起きているのでしょうか,また,回避策はあるのでしょうか

    ②もし回避策がないのであれば,他にどのような方法でDropDownリストから選択すると,直ぐに編集が終了し確定になるか教えていただければと思います。

    よろしくお願い致します。

     

    [参考にさせていただいたサイト]

    http://dobon.net/vb/dotnet/datagridview/selectedindexchanged.html

    [記載したコード]

    ---------------------記載コード---------------------------------------------------

    Public Class Form1
        Private dataGridViewComboBox As DataGridViewComboBoxEditingControl = Nothing

        'EditingControlShowingイベントハンドラ
        Private Sub DataGridView1_EditingControlShowing(ByVal sender As Object, _
                ByVal e As DataGridViewEditingControlShowingEventArgs) _
                Handles DataGridView1.EditingControlShowing
            '表示されているコントロールがDataGridViewComboBoxEditingControlか調べる
            If TypeOf e.Control Is DataGridViewComboBoxEditingControl Then
                Dim dgv As DataGridView = CType(sender, DataGridView)

                '該当する列か調べる
                '編集のために表示されているコントロールを取得
                Me.dataGridViewComboBox = _
                    CType(e.Control, DataGridViewComboBoxEditingControl)
                'SelectedIndexChangedイベントハンドラを追加
                AddHandler Me.dataGridViewComboBox.DropDownClosed, _
                    AddressOf dataGridViewComboBox_DropDownClosed
            End If
        End Sub

        'CellEndEditイベントハンドラ
        Private Sub DataGridView1_CellEndEdit(ByVal sender As Object, _
                ByVal e As DataGridViewCellEventArgs) _
                Handles DataGridView1.CellEndEdit
            'SelectedIndexChangedイベントハンドラを削除
            If Not (Me.dataGridViewComboBox Is Nothing) Then
                RemoveHandler Me.dataGridViewComboBox.DropDownClosed, _
                    AddressOf dataGridViewComboBox_DropDownClosed
                Me.dataGridViewComboBox = Nothing
            End If
        End Sub

        'DataGridViewに表示されているコンボボックスの
        'SelectedIndexChangedイベントハンドラ
        Private Sub dataGridViewComboBox_DropDownClosed(ByVal sender As Object, _
                ByVal e As EventArgs)
            '選択されたアイテムを表示
            Dim cb As DataGridViewComboBoxEditingControl = _
                CType(sender, DataGridViewComboBoxEditingControl)
            DataGridView1.EndEdit()
        End Sub

    End Class

    ---------------------記載コード---------------------------------------------

    2010年10月20日 7:48

回答

  • 1回目の入力が反映されないのは、値に変化があったことがグリッドに伝わっていないためなようです。
    NotifyCurrentCellDirty で通知することで、1回目から入力が反映されるようになりました。

    NotifyCurrentCellDirty をしなくても2回目からは入力できるようになるのは、Closed の後(SelectedIndexChanged の直後)に通知が処理されるためです。
    本来は EndEdit すれば RowHeader の編集中のマーク(鉛筆マーク)は消えるのですが、すぐに NotifyCurrentCellDirty が処理されますので、マークは編集中のままになります。

    ちなみに、もう少しだけコードをシンプルにしてみました。
    RemoveHandler するタイミングは異なりますが、これで十分で問題もないはずです。

    Public Class Form1

        Private Sub DataGridView1_EditingControlShowing(ByVal sender As System.Object, _
                ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) _
                Handles DataGridView1.EditingControlShowing
            Dim cb = TryCast(e.Control, DataGridViewComboBoxEditingControl)
            If cb Is Nothing Then Return
            RemoveHandler cb.DropDownClosed, AddressOf dataGridViewComboBox_DropDownClosed
            AddHandler cb.DropDownClosed, AddressOf dataGridViewComboBox_DropDownClosed
        End Sub

        Private Sub dataGridViewComboBox_DropDownClosed(ByVal sender As Object, _
                ByVal e As EventArgs)
            Dim cb As DataGridViewComboBoxEditingControl = _
                DirectCast(sender, DataGridViewComboBoxEditingControl)
            cb.EditingControlDataGridView.NotifyCurrentCellDirty(True)
            cb.EditingControlDataGridView.EndEdit()
        End Sub

    End Class

    追記:
    同じ行で別のセルに移動しても編集中マークのままになるのは、内部的につじつまが合っていないために思われます(EndEdit 後に Notify が処理されることになるため)。
    動作に問題はなさそうに思いますが、もし不都合でしたら、上記 EndEdit の後に
    cb.EditingControlDataGridView.BeginEdit(False)
    を行ってください。
    また、リストから選択した後に編集中マークが消えるようにしたい場合は、DropDownClosed イベントの中で EndEdit を BeginInvoke するようにします。
    その場合は NotifyCurrentCellDirty や BeginEdit は不要になります。

    • 編集済み TH01 2010年10月20日 10:42 追記
    • 回答としてマーク co8 2010年10月20日 10:55
    2010年10月20日 10:25

すべての返信

  • 1回目の入力が反映されないのは、値に変化があったことがグリッドに伝わっていないためなようです。
    NotifyCurrentCellDirty で通知することで、1回目から入力が反映されるようになりました。

    NotifyCurrentCellDirty をしなくても2回目からは入力できるようになるのは、Closed の後(SelectedIndexChanged の直後)に通知が処理されるためです。
    本来は EndEdit すれば RowHeader の編集中のマーク(鉛筆マーク)は消えるのですが、すぐに NotifyCurrentCellDirty が処理されますので、マークは編集中のままになります。

    ちなみに、もう少しだけコードをシンプルにしてみました。
    RemoveHandler するタイミングは異なりますが、これで十分で問題もないはずです。

    Public Class Form1

        Private Sub DataGridView1_EditingControlShowing(ByVal sender As System.Object, _
                ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) _
                Handles DataGridView1.EditingControlShowing
            Dim cb = TryCast(e.Control, DataGridViewComboBoxEditingControl)
            If cb Is Nothing Then Return
            RemoveHandler cb.DropDownClosed, AddressOf dataGridViewComboBox_DropDownClosed
            AddHandler cb.DropDownClosed, AddressOf dataGridViewComboBox_DropDownClosed
        End Sub

        Private Sub dataGridViewComboBox_DropDownClosed(ByVal sender As Object, _
                ByVal e As EventArgs)
            Dim cb As DataGridViewComboBoxEditingControl = _
                DirectCast(sender, DataGridViewComboBoxEditingControl)
            cb.EditingControlDataGridView.NotifyCurrentCellDirty(True)
            cb.EditingControlDataGridView.EndEdit()
        End Sub

    End Class

    追記:
    同じ行で別のセルに移動しても編集中マークのままになるのは、内部的につじつまが合っていないために思われます(EndEdit 後に Notify が処理されることになるため)。
    動作に問題はなさそうに思いますが、もし不都合でしたら、上記 EndEdit の後に
    cb.EditingControlDataGridView.BeginEdit(False)
    を行ってください。
    また、リストから選択した後に編集中マークが消えるようにしたい場合は、DropDownClosed イベントの中で EndEdit を BeginInvoke するようにします。
    その場合は NotifyCurrentCellDirty や BeginEdit は不要になります。

    • 編集済み TH01 2010年10月20日 10:42 追記
    • 回答としてマーク co8 2010年10月20日 10:55
    2010年10月20日 10:25
  • 返信,ありがとうございます。

    1回目の入力が反映されないのは、値に変化があったことがグリッドに伝わっていないからなのですね。勉強させていただきました。

    上記のコードでテストした結果,1回目から値が入力され,こちらの希望通りの動作を行なうことを確認いたしました。

    初めは何かしらのバグなのかと思い,出来ないと思っていたので実現することができて感激しております。

    繰り返しになりますが,ありがとうございました。

     

     

    • 回答としてマーク co8 2010年10月20日 10:55
    • 回答としてマークされていない co8 2010年10月20日 10:55
    2010年10月20日 10:55