- PR -

DataGridViewのヘッダーにチェックボックス

投稿者投稿内容
Haru
常連さん
会議室デビュー日: 2009/02/18
投稿数: 37
投稿日時: 2009-03-03 13:25
引用:

今回作成したクラス内でのみRows(0).Cells(0)に特別な意味があるように思えますが


Rows(0).Cells(0)ではなく、カーソルがあるセルの設定がスキップされるようです。
初期値だとRows(0).Cells(0)にカーソルがあるので気付きませんでした。
私には原因が思いつかないのですが何か参考になりませんでしょうか?
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2009-03-03 17:39
編集モードが開始されているからでしょう。
そのセルのIsInEditModeプロパティ値はTrueになっているはずです。

編集モードが開始されているセルを更新する場合
一度編集モードを確定または取消してから
更新してください。

編集モードの有無:DataGridViewCell.IsInEditMode
編集モードの確定:DataGridView.EndEdit()
編集モードの取消;DataGridView.CancelEdit()

[追記]
編集モードを続行したまま値の更新を行うには
値変更後にDataGridViewCell.RefreshEdit()を呼びます。
ただし現在の値を基とし、以前の値は破棄される為
後に編集モードを取消しても、編集モード開始前の値には戻りませんのでご注意ください。


[ メッセージ編集済み 編集者: くまっち 編集日時 2009-03-03 17:59 ]
Haru
常連さん
会議室デビュー日: 2009/02/18
投稿数: 37
投稿日時: 2009-03-03 18:24
引用:

くまっちさんの書き込み (2009-03-03 17:39) より:
編集モードが開始されているからでしょう。
そのセルのIsInEditModeプロパティ値はTrueになっているはずです。

編集モードが開始されているセルを更新する場合
一度編集モードを確定または取消してから
更新してください。



確かにおっしゃる通りでした。
設定前にIsInEditModeを確認し編集モードの確定をするようにしたら
カーソルのあるセルも値を変更することができました。

残る問題はPaintの件です。
こちらについては今の処はMe.RaiseCellValueChanged(e)を入れて
凌いでいますが本当はどうするべきか分かりません
Haru
常連さん
会議室デビュー日: 2009/02/18
投稿数: 37
投稿日時: 2009-03-04 16:45
引用:

残る問題はPaintの件です。
こちらについては今の処はMe.RaiseCellValueChanged(e)を入れて
凌いでいますが本当はどうするべきか分かりません



マシンを変えて試したらMe.RaiseCellValueChanged(e)が無くても動きました。
VS2008に関しては同じオプションでインストールしましたが、他はまったくと
いっていい程異なる環境です。
何台か(Pen4,Celeron,Core2 DUO)で試しましたがCore2DUOのマシンしか動きませんでした。
CPUの違いなんてことがあるのでしょうか???
ますますわからなくなりました・・・

[ メッセージ編集済み 編集者: Haru 編集日時 2009-03-04 16:47 ]
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2009-03-05 09:26
Paintを発生させるためにRaiseCellValueChangedを使うよりは
Me.DataGridView.InvalidateCell(Me)と呼び出したほうが適切かなぁと思います。
RaiseCellValueChanged:Value値の変化(Valueはヘッダテキストなのでイベントが不適切かと)
InvalidateCell:セルの再描画

CPUの違いでPaintが発生するかどうかが決まるなんて聞いたことはないですねぇ。
.NETFrameworkのバージョン違いかなとも思っていましたが・・・。
Haru
常連さん
会議室デビュー日: 2009/02/18
投稿数: 37
投稿日時: 2009-03-05 11:44
引用:

くまっちさんの書き込み (2009-03-05 09:26) より:
Paintを発生させるためにRaiseCellValueChangedを使うよりは
Me.DataGridView.InvalidateCell(Me)と呼び出したほうが適切かなぁと思います。
RaiseCellValueChanged:Value値の変化(Valueはヘッダテキストなのでイベントが不適切かと)
InvalidateCell:セルの再描画


ありがとうございます。
試してみます。


引用:

CPUの違いでPaintが発生するかどうかが決まるなんて聞いたことはないですねぇ。
.NETFrameworkのバージョン違いかなとも思っていましたが・・・。


.NETFrameworkのバージョンは同じ3.5です。
OSはXPなのですがHome(Pen4,Celeron)とPro(Core2DUO)ですが、SP3まで当てています。
Vistaはまだ試していません。
Haru
常連さん
会議室デビュー日: 2009/02/18
投稿数: 37
投稿日時: 2009-03-06 10:19
Me.DataGridView.InvalidateCell(Me)にすることで安定して動作させることができました。
ありがとうございました。

せっかく教えて頂きましたので以下に今回教えて頂いた内容を纏めた
最終版のコードを掲載します。


コード:
【DataGridViewCustomCheckBoxHeaderColumn】
Imports System.Windows.Forms
Imports System.ComponentModel

'' カスタム列ヘッダクラスを使用するカスタム列クラス
Public Class DataGridViewCustomCheckBoxHeaderColumn
    Inherits DataGridViewCheckBoxColumn

    Public Sub New()
        MyBase.DefaultHeaderCellType = GetType(DataGridViewCustomCheckBoxHeaderCell)

        '' ソート方向を示すグリフ表示をさせないためにソート不可(コード上からのソートのみ)に設定
        Me.SortMode = DataGridViewColumnSortMode.NotSortable
    End Sub

    <EditorBrowsable(EditorBrowsableState.Never), Browsable(False), _
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
    Public Shadows ReadOnly Property DefaultHeaderCellType() As Type
        Get
            Return GetType(DataGridViewCustomCheckBoxHeaderCell)
        End Get
    End Property

End Class

【DataGridViewCustomCheckBoxHeaderCell】
Imports System.Windows.Forms
Imports System.ComponentModel

'' カスタム列ヘッダセル
Public Class DataGridViewCustomCheckBoxHeaderCell
    Inherits DataGridViewColumnHeaderCell

    Private _checkState As Boolean

    Protected Overrides Sub Paint( _
        ByVal graphics As Graphics, _
        ByVal clipBounds As Rectangle, _
        ByVal cellBounds As Rectangle, _
        ByVal rowIndex As Integer, _
        ByVal cellState As DataGridViewElementStates, _
        ByVal value As Object, _
        ByVal formattedValue As Object, _
        ByVal errorText As String, _
        ByVal cellStyle As DataGridViewCellStyle, _
        ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, _
        ByVal paintParts As DataGridViewPaintParts)

        '' 既存のヘッダーは背景や枠だけ描画すればいいので、テキストは空指定
        MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, _
            cellState, String.Empty, String.Empty, String.Empty, cellStyle, _
             advancedBorderStyle, paintParts)

        '' 文字描画の必要領域を求める
        Dim drawTextSize As SizeF
        drawTextSize = graphics.MeasureString(formattedValue, cellStyle.Font)

        '' チェックボックス本体の描画位置を求める
        Dim location As New Point
        location.X = cellBounds.X + (cellBounds.Width - drawTextSize.Width) / 2 - 16
        location.Y = cellBounds.Y + (cellBounds.Height - 12) / 2

        '' チェック状態からCheckBoxStateを求める
        Dim checkBoxState As VisualStyles.CheckBoxState
        checkBoxState = IIf(Me._checkState, _
            VisualStyles.CheckBoxState.CheckedNormal, VisualStyles.CheckBoxState.UncheckedNormal)
        Console.WriteLine("Paint: checkBoxState=" & checkBoxState.ToString())
        '' チェックボックスを描画
        System.Windows.Forms.CheckBoxRenderer.DrawCheckBox( _
            graphics, location, cellBounds, formattedValue, cellStyle.Font, False, checkBoxState)
    End Sub

    Protected Overrides Sub OnClick(ByVal e As System.Windows.Forms.DataGridViewCellEventArgs)
        _checkState = _checkState Xor True
        Console.WriteLine("_checkState=" & _checkState.ToString())
        MyBase.OnClick(e)
        Me.RaiseCheckBoxCheckedChanged(EventArgs.Empty)
        Me.DataGridView.InvalidateCell(Me)
    End Sub
    
    Protected Overrides Sub OnDoubleClick(ByVal e As System.Windows.Forms.DataGridViewCellEventArgs)
        _checkState = _checkState Xor True
        MyBase.OnDoubleClick(e)
        Me.RaiseCheckBoxCheckedChanged(EventArgs.Empty)
        Me.DataGridView.InvalidateCell(Me)
    End Sub

    Private Sub RaiseCheckBoxCheckedChanged(ByVal e As EventArgs)
        '' チェックボックスの状態(On/Off)が変化した時の処理は以下に記述
        '' サンプル
        Console.WriteLine(String.Format("チェックボックスが[{0}]になりました。", _
            IIf(Me._checkState, "On", "Off")))
    End Sub

    Public Property Checked() As Boolean
        Get
            Return _checkState
        End Get
        Set(ByVal value As Boolean)
            _checkState = value
        End Set
    End Property

End Class

【Form】
    Private Sub DataGridView1_ColumnHeaderMouseClick(ByVal sender As System.Object, 
                ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs) 
                Handles DataGridView1.ColumnHeaderMouseClick
        DataGridView1_Check(sender, e)
    End Sub


    Private Sub DataGridView1_ColumnHeaderMouseDoubleClick(ByVal sender As System.Object, 
                ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs) 
                Handles DataGridView1.ColumnHeaderMouseDoubleClick
        DataGridView1_Check(sender, e)
    End Sub

    Private Sub DataGridView1_Check(ByVal sender As System.Object, 
                ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs)
        If DataGridView1.Columns(e.ColumnIndex).Name = "Column1" Then
            Dim cell As DataGridViewCustomCheckBoxHeaderCell = _
                DirectCast(DataGridView1.Columns(e.ColumnIndex).HeaderCell,  _
                DataGridViewCustomCheckBoxHeaderCell)

            Dim flag As Boolean = False
            flag = cell.Checked
            Dim dRow As DataGridViewRow
            For Each dRow In DataGridView1.Rows
                If dRow.Cells(0).IsInEditMode = True Or _
                  dRow.Cells(2).IsInEditMode = True Or _
                  dRow.Cells(3).IsInEditMode = True Then
                    DataGridView1.EndEdit()
                End If
                dRow.Cells(0).Value = flag
                dRow.Cells(2).Value = flag
                dRow.Cells(3).Value = flag
            Next
        End If
    End Sub



スキルアップ/キャリアアップ(JOB@IT)