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) ThenUsing 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.FontsubEditor.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 IfEnd 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
ロジックとしてはこんな感じかと。ここまでの記事で用意した拡張メソッドやらなんやらてんこもりなので、昔の記事も色々と見てください。
私もユーザーコントロールをDataGridViewに表示させようと試行錯誤しています。
返信削除セルをクリックして編集モードで表示するまではできたのですが、最初から表示させることができません。
こちらの一連のご説明が非常に参考になるのですが、私のスキルでは完全に理解できてないです。
プログラム全体のサンプルを公開していただくことはできないでしょうか?
コメントありがとうございます。
返信削除実際にDataGridViewで色々やっていたのが、結構昔なのでお恥ずかしいのですが、近いうちに公開しようと思います。
1~2日中に準備しますので、少々お待ちください。
随分過去の記事にコメントして申し訳ございません。
返信削除他では有力な情報が得られないため、何卒お願い致します。m(__)m
いえいえ、見てもらえるだけでも嬉しいですよ!
返信削除過去に利用していたソースを用意してみましたので、こちらを参照してみてください。
http://blogahf.blogspot.jp/2014/12/datagridview.html