将可点击按钮添加到自定义 DataGridViewCell 控件

Add clickable buttons to a custom DataGridViewCell control

我制作了一个自定义 DataGridViewColumn 控件及其 DataGridViewCell 控件。 这个想法是在数据绑定时动态创建单元格的内容,它由一系列可点击的功能按钮组成。按钮的数量和种类取决于传递的数据值。

为此,我覆盖了 DataGridViewCell 的 Paint 方法并检查其内容上的 formattedValue 并相应地绘制按钮。但是,这些按钮是 "dead" 并且不可点击,所以问题是如何使它们可点击,即如何为点击事件添加处理程序?

我是否必须覆盖单元格的 OnClick 方法,然后尝试查明具体单击了哪个按钮?这可能吗?有更好的方法吗?

这是我目前得到的:

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

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

    Dim cellBackground As New SolidBrush(cellStyle.BackColor)
    graphics.FillRectangle(cellBackground, cellBounds)
    cellBackground.Dispose()

    PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle)

    Dim sValue As String = formattedValue.ToString()

    If (sValue.Contains("ViewAsPDF")) Then

        Dim buttonArea As Rectangle = cellBounds
        Dim buttonAdjustment As Rectangle = Me.BorderWidths(advancedBorderStyle)
        buttonArea.X += buttonAdjustment.X
        buttonArea.Y += buttonAdjustment.Y
        buttonArea.Height -= buttonAdjustment.Height
        buttonArea.Width -= buttonAdjustment.Width
        buttonArea.Width = buttonArea.Width / 4
        ButtonRenderer.DrawButton(graphics, buttonArea, PushButtonState.Default)
        TextRenderer.DrawText(graphics, "PDF", Me.DataGridView.Font, buttonArea, SystemColors.ControlText)

    End If

   'etcetera 

End Sub

我想你可能走错路了。根据提供的代码,您只需将单元格绘制成 看起来像 它们包含按钮。由于它们实际上不是对象,因此它们无法引发事件。

I don't understand ButtonRenderer, if you can't create actual Buttons with it

ButtonRender不会创建一个新的按钮对象,它是用来按钮对象来绘制的.通常一个 subclassed 按钮不会使用它,因为它使用了现有的主题和样式,这可能是您想要做的不同的事情(甚至 DataGridViewButtonCell 也不使用它——在至少不是直接的)。

从提供的代码来看,它似乎每次都在运行中计算每个按钮,而不是从某个集合或定义中绘制。如果 "action" 列表需要根据行而变化(例如,DOC、XLS 或图像行的不同操作)怎么办?这样做似乎需要大量代码。


你现在的课程可能不是不可能,但也不是微不足道的。您可能 能够创建一组虚拟按钮(基本上是绘制时的 Rect)并像您所做的那样渲染它们。然后在cell-click事件中,translate/adjustX位置看哪个矩形包含thisPt.X来决定采取哪个相关动作。

还有"issues"比如当用户调整列大小时会发生什么?当按钮列表因某些其他单元格值(DOC vs XLS vs IMG vs PDF)而变化时怎么办?这将需要一组按钮集...和大量代码。

这并不是说它不能完成,但似乎需要大量代码才能使其更加灵活。


Are there better ways?

我也这么认为。

一个更简单的现有解决方案可能是使用现有的 DataGridViewComboBoxColumn 来存储 "Actions" 或 "Activities"。它看起来不那么混乱,而且对用户更友好:

只需少量代码即可为每种动物提供不同的列表:

' dogs like to go for walks
Private ActsCan() As String = {"Feed", "Pet", "Bathe", "Brush", "Take for Walk"}
' no walks or baths for cats
Private ActsFel() As String = {"Feed", "Pet", "Baby-Talk To", "Brush"}
' never bathe a Mugwai, comb rather than brush
Private ActsMug() As String = {"Feed", "Pet", "Baby-Talk To", "Comb"}
Private ActsGrem() As String = {"Hide From", "Strangle"}
...
Private Sub dgv_RowEnter(sender As Object, 
          e As DataGridViewCellEventArgs) Handles dgv.RowEnter

    Dim dgvCBO As DataGridViewComboBoxCell
    dgvCBO = CType(dgv.Rows(e.RowIndex).Cells("ColActs"), DataGridViewComboBoxCell)
    dgvCBO.Items.Clear()
    Select Case dgv.Rows(e.RowIndex).Cells("colSpecies").Value.ToString
        Case "Canine"
            dgvCBO.Items.AddRange(ActsCan)
        Case "Feline"
            dgvCBO.Items.AddRange(ActsFel)
        Case "Mugwai"
            dgvCBO.Items.AddRange(ActsMug)
        Case "Gremlin"
            dgvCBO.Items.AddRange(ActsGrem)
    End Select
End Sub

A class 封装大部分 可能对未绑定的 DGV 很好。可以优化当thisRow的触发值与上一个相同时不重建列表。

这个方法怎么样。仅实施 ui.