トップ回答者
DataGridViewのコンボボックスで,DropDownListから値を選択した際に,編集中のセルを確定させたい

質問
-
他に同様な質問がなかったため,起票させていただきます。
内容は,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---------------------記載コード---------------------------------------------
回答
-
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 は不要になります。
すべての返信
-
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 は不要になります。 -