QA@IT

.Net DataGridView ユーザコントロールセルのボタンのクリック

5803 PV

http://qa.atmarkit.co.jp/q/4110?_nid=4560

こちらの方で、DataGridViewに複数コントロールを配置したユーザーコントロールを
表示させる方法を質問させていただき、一応できるようになりました。
ただ他の問題があり、別質問にさせていただきました。

ユーザーコントロールにはボタンを置いていますが、このボタンをクリックするには
セルを何回かクリックして編集モードにした後でないとできません。

標準で用意されているDataGridViewButtonColumnのように、最初からクリックできる状態で
表示したいのですが、何が足りないでしょうか?

http://msdn.microsoft.com/ja-jp/library/system.windows.forms.buttonrenderer(v=vs.110).aspx
DataGridViewButtonCellのソースコードを見てDataGridViewButtonCellRendererクラスが怪しいと思うのですが、
私のスキルが追いつかず理解できてません。

マウスカーソルをセルにのせるだけで編集モードにする方法も考えているのですが、
CellEnterイベント等にBeginEditメソッドを使ってみましたが、意図した動きになりません。

そもそもできるのかどうかもわからなくなってきたのですが、何かアドバイスいただけたら非常にありがたいです。

ユーザーコントロールのVBコードをあげておきます。
デザインとしてはラベルとボタンを配置しています。
よろしくお願い致します。

Friend Class MyControl
    Inherits UserControl
    Implements IDataGridViewEditingControl

    Private Const SRCCOPY As Integer = &HCC0020

    ''' <summary>BitBlt Win32Apiの定義</summary><exclude />
    <System.Runtime.InteropServices.DllImport("gdi32.dll")> _
    Private Shared Function BitBlt(ByVal hdcDest As IntPtr, _
            ByVal nXDest As Integer, ByVal nYDest As Integer, _
            ByVal nWidth As Integer, ByVal nHeight As Integer, _
            ByVal hdcSrc As IntPtr, _
            ByVal nXSrc As Integer, ByVal nYSrc As Integer, _
            ByVal dwRop As Integer) As Boolean
    End Function

    Private dataGridViewControl As DataGridView
    Private valueIsChanged As Boolean = False
    Private rowIndexNum As Integer

    Private _Value As MyOriginalCellValue.Value
    Public Property Value() As MyOriginalCellValue.Value
        Get
            Return _Value
        End Get
        Set(ByVal value As MyOriginalCellValue.Value)
            _Value = value
        End Set
    End Property


    Public Property EditingControlFormattedValue() As Object _
        Implements IDataGridViewEditingControl.EditingControlFormattedValue

        Get
            Return Me._Value
        End Get

        Set(ByVal value As Object)
            Try
                ' This will throw an exception of the string is 
                ' null, empty, or not in the format of a date.
                Me._Value = value
            Catch
                ' In the case of an exception, just use the default
                ' value so we're not left with a null value.
                Me._Value = MyOriginalCellValue.Value.Null
            End Try
        End Set

    End Property

    Public Function GetEditingControlFormattedValue(ByVal context _
        As DataGridViewDataErrorContexts) As Object _
        Implements IDataGridViewEditingControl.GetEditingControlFormattedValue

        Return Me._Value

    End Function

    Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As  _
        DataGridViewCellStyle) _
        Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl

        Me.Font = dataGridViewCellStyle.Font

    End Sub

    Public Property EditingControlRowIndex() As Integer _
        Implements IDataGridViewEditingControl.EditingControlRowIndex

        Get
            Return rowIndexNum
        End Get
        Set(ByVal value As Integer)
            rowIndexNum = value
        End Set

    End Property

    Public Function EditingControlWantsInputKey(ByVal key As Keys, _
        ByVal dataGridViewWantsInputKey As Boolean) As Boolean _
        Implements IDataGridViewEditingControl.EditingControlWantsInputKey

        ' Let the DateTimePicker handle the keys listed.
        Select Case key And Keys.KeyCode
            Case Keys.Left, Keys.Up, Keys.Down, Keys.Right, _
                Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp

                Return True

            Case Else
                Return Not dataGridViewWantsInputKey
        End Select

    End Function

    Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean) _
        Implements IDataGridViewEditingControl.PrepareEditingControlForEdit

        ' No preparation needs to be done.

    End Sub

    Public ReadOnly Property RepositionEditingControlOnValueChange() _
        As Boolean Implements _
        IDataGridViewEditingControl.RepositionEditingControlOnValueChange

        Get
            Return False
        End Get

    End Property

    Public Property EditingControlDataGridView() As DataGridView _
        Implements IDataGridViewEditingControl.EditingControlDataGridView

        Get
            Return dataGridViewControl
        End Get
        Set(ByVal value As DataGridView)
            dataGridViewControl = value
        End Set

    End Property

    Public Property EditingControlValueChanged() As Boolean _
        Implements IDataGridViewEditingControl.EditingControlValueChanged

        Get
            Return valueIsChanged
        End Get
        Set(ByVal value As Boolean)
            valueIsChanged = value
        End Set

    End Property

    Public ReadOnly Property EditingControlCursor() As Cursor _
        Implements IDataGridViewEditingControl.EditingPanelCursor

        Get
            Return MyBase.Cursor
        End Get

    End Property

    Protected Sub OnValueChanged(ByVal eventargs As EventArgs)

        ' Notify the DataGridView that the contents of the cell have changed.
        valueIsChanged = True
        Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)

    End Sub



    Public Function CreateControlImage(ByVal visibleStatus As Boolean) As System.Drawing.Bitmap
        Dim _controlImage As New System.Drawing.Bitmap(Me.Width, Me.Height)

        If visibleStatus Then
            'ダミーコントロールの追加
            Dim dummyControl As New System.Windows.Forms.TextBox
            With dummyControl
                .Name = "dummy"
                .Size = New System.Drawing.Size(0, 0)
            End With
            Me.Controls.Add(dummyControl)
            dummyControl.Focus()
            Me.Refresh()

            Dim targetControl As System.Windows.Forms.Control = Nothing
            Dim targetGraphic As System.Drawing.Graphics = Nothing

            targetControl = Me
            targetGraphic = targetControl.CreateGraphics
            Dim paintArgs As New System.Windows.Forms.PaintEventArgs(targetGraphic, targetControl.ClientRectangle)
            Me.OnPaint(paintArgs)

            'GraphicsオブジェクトよりBitmapオブジェクトのコピー
            Using contGrap As System.Drawing.Graphics = targetGraphic
                Dim originalHdc As IntPtr = contGrap.GetHdc
                Using bmpGrap As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(_controlImage)
                    Dim targetHdc As IntPtr = bmpGrap.GetHdc
                    MyControl.BitBlt(targetHdc, 0, 0, targetControl.Width, targetControl.Height, _
                                              originalHdc, targetControl.Left, targetControl.Top, SRCCOPY)
                    bmpGrap.ReleaseHdc(targetHdc)
                End Using
                contGrap.ReleaseHdc(originalHdc)
            End Using
            targetGraphic.Dispose()
            targetControl = Nothing

            Me.Controls.Remove(dummyControl)
        Else
            '非表示時のキャプチャ
            Me.Visible = True
            Me.DrawToBitmap(_controlImage, New System.Drawing.Rectangle(0, 0, Me.Width, Me.Height))
        End If

        Return _controlImage
    End Function

End Class

回答

自己解決できたと思われます。

CellMouseEnterイベントで、引数からマウスカーソルが入ったセルの位置を元にそのセルを
アクティブにして、編集モードにすれば思った動きになりました。

    Private Sub DataGridView1_CellMouseEnter(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellMouseEnter
        If e.ColumnIndex >= 0 And e.RowIndex >= 0 Then
            DataGridView1.CurrentCell = DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex)
        End If

        DataGridView1.BeginEdit(False)

    End Sub
編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。