kei0425tan’s blog

技術的なことを主に

.Net DataGridViewのセルのチェックボックスの制御

DataGridView便利でよくつかいますよね?

日本人は表が好きなので、なんでもグリッドにすることが多いかと思います。

そこで、グリッドのセルにチェックボックスも、ウィザードで簡単に追加できるかと思います。
データの設定も、grid.DataSource = で一発で設定できるし便利便利!!

と思っていたのですが、チェックボックスの制御をしようと思うと途端に難しくなります。
普通は、各オブジェクトからイベントが発生するので、そのイベントに応じて処理を書けばよいのですが、DataGridViewのセルのチェックボックスからはイベントが発生しません。
普通は、CheckedChanged、CheckStateChanged、Clickなどのイベントを拾えるのに、、、、、


なので、定石としては、親のDataGridViewのCellMouseClickを拾うのがよいそうです。

ただし、全てのセルに対して、マウスクリックイベントが発生するため、DataGridViewのCellMouseClickを拾ったあとは
eから、RowIndexとColumnIndexを取得し、どのセルがクリックされたかを特定してイベントの処理を行います。

注意点としましては、DataGridViewのCellMouseClickを実行したあと、拾えない内部のチェックボックスのクリックイベントが発生して、データの書き換えを行うようなので、ダイアログボックスを表示したりすると表示がちぐはぐになります。
さらに、キャンセルをしたくても、強制的にチェックボックスのクリックイベントが発生するため、キャンセルできません。

対応するためには、DataGridViewでチェックボックスを定義する際には、ReadOnly = Trueに設定しておきましょう。
それによって、チェックボックスのオンオフのイベントは発生しません。
勝手に変わらないため、CellMouseClickイベントで自力でON/OFFの制御をしましょう。

というわけでサンプルです。

DataGridViewを作成し、列として、3つチェックボックスを追加しています。
ReadOnlyはTrueにしています。

f:id:kei0425tan:20170315155805j:plain

制御用のコードはこちら
If で判定して成立した場合には自力でValueを反転しています。
成立しない場合には、メッセージボックスを出力しています。

試しに、ReadOnlyをFalseにするとおかしな動きをするのがわかると思います。

    Private Sub DataGridView1_CellMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseClick
        Dim columnIndex = e.ColumnIndex
        Dim rowIndex = e.RowIndex
        Dim dgv As DataGridView = sender
        Dim row = dgv.Rows(e.RowIndex)
        If columnIndex = 0 OrElse row.Cells(columnIndex - 1).Value Then
            row.Cells(columnIndex).Value = Not row.Cells(columnIndex).Value
        Else
            MessageBox.Show("左のチェックボックスがONでないと変更できません。")
        End If
    End Sub