2007年9月4日火曜日

伝票レイアウトセル(5) セル その3

Paintメソッドでイメージを表示させるにあたってもう一つ考えておく必要がある話題が。

というのも、このPaintメソッド自体はやたらめったらに呼ばれるから。
「マウスを動かす」「キーを押す」などDataGridViewでちょっとでも変更が起きそうな際には必ず呼ばれる。
なのでそのあたりを考慮しておかないと、もともとコストの高いイメージキャプチャ処理なので重いAPとなってしまうわけだ。

んじゃ何をもって判断してあげればよいかというと。

  • DataGridViewElementStates
  • DataGridViewCellStyle

この二つ。DataGridViewElementStatesは引数elementstateに設定されて、DataGridViewCellStyleは引数cellstyleに設定されてくる。これらの中身をセルレベルで保持させておいて、Paintメソッドの都度引数と保持したものとを比較し、異なる際に限ってイメージのキャプチャと描写処理を行ってあげるのがベターだと思う。
・・・多分もう少し適切な方法もあるとは思うんだけど。

ちなみにelementstateはEnumなのでそのまま保持だけど、cellstyleはClassなので、cellstyle.Cloneの結果を保持するようにしておく必要があるね。そうしないと引数と保持しているものが同じものを参照してしまう。

''' <summary>現在の DataGridViewCell を描画します。</summary>
Protected Overrides Sub Paint(ByVal graphics As System.Drawing.Graphics, _
                              ByVal clipBounds As System.Drawing.Rectangle, _
                              ByVal cellBounds As System.Drawing.Rectangle, _
                              ByVal rowIndex As Integer, _
                              ByVal elementState As System.Windows.Forms.DataGridViewElementStates, _
                              ByVal value As Object, _
                              ByVal formattedValue As Object, _
                              ByVal errorText As String, _
                              ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, _
                              ByVal advancedBorderStyle As System.Windows.Forms.DataGridViewAdvancedBorderStyle, _
                              ByVal paintParts As System.Windows.Forms.DataGridViewPaintParts)

    MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)

    If Me._editorInstanceType Is Nothing Then Return
    If (_beforeState <> elementState) OrElse _
       (_beforeCellStyle Is Nothing) OrElse _
       (Not _beforeCellStyle.ToString = cellStyle.ToString) Then

        Using subEditor As MultiLayoutControl _
            = TryCast(System.Activator.CreateInstance(Me._editorInstanceType), MultiLayoutControl)

            If subEditor Is Nothing Then Return

            subEditor.Top = subEditor.Height * -1
            subEditor.Left = subEditor.Width * -1
            If (Me.DataGridView IsNot Nothing) AndAlso _
               (Me.DataGridView.TopLevelControl IsNot Nothing) Then
                Me.DataGridView.TopLevelControl.SuspendLayout()
                Me.DataGridView.TopLevelControl.Controls.Add(subEditor)
            End If

            '色とフォントの設定
            If (elementState And DataGridViewElementStates.Selected) = DataGridViewElementStates.Selected Then
                subEditor.BackColor = cellStyle.SelectionBackColor
                subEditor.ForeColor = cellStyle.SelectionForeColor
            Else
                subEditor.BackColor = cellStyle.BackColor
                subEditor.ForeColor = cellStyle.ForeColor
            End If
            subEditor.Font = cellStyle.Font

            subEditor.Values = TryCast(value, SubEditor.SubEditorValues)
            subEditor.OnConvertValuesToInterface()
            'イメージキャプチャのメソッドを呼び出す
            _controlImage = subEditor.CreateControlImage(False)

            If (Me.DataGridView IsNot Nothing) AndAlso _
               (Me.DataGridView.TopLevelControl IsNot Nothing) Then
                Me.DataGridView.TopLevelControl.Controls.Remove(subEditor)
                Me.DataGridView.TopLevelControl.ResumeLayout()
            End If

        End Using
        _beforeState = elementState
        _beforeCellStyle = cellStyle.Clone
    End If

    'イメージの描写
    graphics.DrawImage(_controlImage, cellBounds.X, cellBounds.Y, _controlImage.Width, _controlImage.Height)
    '枠線が必要な際は描写
    If (paintParts And DataGridViewPaintParts.Border) = DataGridViewPaintParts.Border Then
        MyBase.PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle)
    End If
End Sub

ロジックとしてはこんな感じかと。ここまでの記事で用意した拡張メソッドやらなんやらてんこもりなので、昔の記事も色々と見てください。

4 件のコメント:

  1. 私もユーザーコントロールをDataGridViewに表示させようと試行錯誤しています。
    セルをクリックして編集モードで表示するまではできたのですが、最初から表示させることができません。
    こちらの一連のご説明が非常に参考になるのですが、私のスキルでは完全に理解できてないです。
    プログラム全体のサンプルを公開していただくことはできないでしょうか?

    返信削除
  2. コメントありがとうございます。
    実際にDataGridViewで色々やっていたのが、結構昔なのでお恥ずかしいのですが、近いうちに公開しようと思います。
    1~2日中に準備しますので、少々お待ちください。

    返信削除
  3. 随分過去の記事にコメントして申し訳ございません。
    他では有力な情報が得られないため、何卒お願い致します。m(__)m

    返信削除
  4. いえいえ、見てもらえるだけでも嬉しいですよ!

    過去に利用していたソースを用意してみましたので、こちらを参照してみてください。
    http://blogahf.blogspot.jp/2014/12/datagridview.html

    返信削除