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

DataGridViewのCheckBoxColumnのCheckChangeを捉える

環境/言語:[Windows7 VB.net]
分類:[.NET]

DataGridViewのCheckBoxColumnのCheck状態が「変わった」というイベントが、
マウスのアップ時に、EndEditイベントなどによってタイムリーに拾えない
現象について解決を探してます。

具体的に言うと、CheckBoxの場合、EndEditイベントはマウスのアップ時に
ではなく、そのセルからフォーカスが他のセルに移った時に初めて起こる
ので、セル上にチェックマークが描かれた瞬間のイベント発生とはならない
のです。

これを解決するために、他のイベント(ValueChangedや、EditingControlShowing
)の活用を検討しましたが、どれもうまく行きませんでした。

最終的には以下のような自作クラスによってしか解決しないという結論に
達したのですが、どうも他にもっと良い方法がないものかと気になっています。

もし何かあればご教授頂ければ幸いです。


Public Class MyDgv
'※DataGridView上にCheckBoxColumnは一つしかないという前提での造りです
Inherits DataGridView

Private pri_lastcontentclicked_ind As Integer = -1
Private pri_lastmouseup_ind As Integer = -1

Private Shadows Sub CellContentClick(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _
Handles MyBase.CellContentClick

If Not TypeOf (MyBase.Columns(e.ColumnIndex)) Is DataGridViewCheckBoxColumn Then Return
pri_lastcontentclicked_ind = e.RowIndex

End Sub
Private Shadows Sub CellMouseUp(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs) _
Handles MyBase.CellMouseUp

If e.ColumnIndex = -1 Then Return
If Not TypeOf (MyBase.Columns(e.ColumnIndex)) Is DataGridViewCheckBoxColumn Then Return

If pri_lastcontentclicked_ind = -1 Then Return
If pri_lastcontentclicked_ind = e.RowIndex Then
'直前に起こったCellContentClickのindexと、このMouseUpイベントのindexが同じ場合は、
'チェックが変わったとみなす

'CheckChange時に行いたい処理は、他のTextColumnなどのEndEdit時とひとまとめにして、 
'EndEditイベントハンドラに集約して書くという考え方をとるので
'ここでEndEditを誘発するのが合理的(と考える)
MyBase.EndEdit()
End If
End Sub

End Class
※ちなみに投稿時にソースのIndent部分が全て、左に寄って
しまう現象は、回避する方法は無いでしょうか? 
■No31114に返信(kane123さんの記事)
> ※ちなみに投稿時にソースのIndent部分が全て、左に寄って
> しまう現象は、回避する方法は無いでしょうか? 
> 
> 
図表モードでも駄目かな?(Comment投稿のちょっと上のオプションボタン)
こんなのでいいのかな。
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        DataGridView1.RowCount = 10
        Dim column As New DataGridViewCheckBoxColumn()
        DataGridView1.Columns.Add(column)
    End Sub

    Private Sub DataGridView1_CellMouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseUp
        Dim cell As DataGridViewCheckBoxCell
        cell = DirectCast(DataGridView1(e.ColumnIndex, e.RowIndex), DataGridViewCheckBoxCell)
        Console.WriteLine("Row={0} Col={1}, Check={2}", e.RowIndex, e.ColumnIndex, cell.EditingCellFormattedValue)
    End Sub
なるほど!
GODさん、ありがとうございます。
次回から活用させて頂きます。
GODさん、すみません。
頂いた返信のソース部分は、最初「図表モード」の例かと勘違いし、回答が
遅れました。

DataGridViewCheckBoxCellオブジェクトの
EditingCellFormattedValueプロパティを使うというのが
ミソなのですね。ありがとうございます。

ただ、この方法だとDataGridViewCellの余白部分(非Content領域)で
MouseUpが起こった場合(つまりValueのTrue/Falseは切り替わらなかったけど、MouseUpが起こった場合)も処理が起こるということになりますね。
そうなると
MouseUp前:True MouseUp後:True
という場合でも処理が行われるということになります。

あくまで
MouseUp前:True MouseUp後:False
という場合だけで処理を行わせ
たいと思うと、やはり最初に書いたようにContentClickイベントとMouseUPイベント
を組み合わせた処理が必要になるのではないかと思います。

とはいえ、DataGridViewCheckBoxCellの
EditingCellFormattedValueプロパティは知りませんでし、参考になりました。
今後に活かせそうです。ありがとうございました。
やっぱり、私間違っていました。

EditingCellValueChangedプロパティというものがあることに
気づきました。

上記のGODさんのソースに追加する形で
If cell.EditingCellValueChanged = True Then
'処理行う
Else
  '処理行わない 
End If

で分岐させればいいのですね。こうすれば、チェックが切り
替った時にだけ処理を行うことができます。
これで最終解決に至りました。
GODさん、ありがとうございます!深謝です。
(解決済みとします)
解決済み!
■No31119に返信(kane123さんの記事)
> EditingCellValueChangedプロパティというものがあることに
> 気づきました。
>
EditingCellValueChangedではちょっと無理そうですねorz

EditingCellValueChangedは一発目はtrueになるけど、セル移動(データ確定)するまではfalseにならない。
再現:
1.チェックボックスにチェックを付ける。(...FormattedValue=true, ValueChanged=true)
2.同じセルの空白部をクリック。(...FormattedValue=true, ValueChanged=true)

true→true, false→falseで処理を行わないようにするのなら、私の方法だと前回値(row,col,value)を覚えるしかないのかな。

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