VB.NET学习笔记:winForm扩展DataGridView控件实现一列多操作(如查看详情、修改、删除等)按钮

使用DataGridView控件时需要每一行都有一个查看、修改、删除按钮,可以添加按钮列来实现,可是每一列只能有一个按钮,怎么看都不够美观,于是想能不能在单元格把按钮给画上去。
实例下载链接:https://download.csdn.net/download/zyjq52uys/12456524
效果图如下:
一列多操作按钮
在这里插入图片描述
在这里插入图片描述

直接上代码:
DataGridViewEx:

Public Class DataGridViewEx
    Inherits DataGridView
        ''' <summary>
    ''' 修改按钮点击事件
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    <Category("自定义事件"), Description("修改按钮点击事件")>
    Public Event CellButtonModifyClicked(ByVal sender As Object, ByVal e As EventArgsEx.DataGridViewClickEventArgsEx)
    ''' <summary>
    ''' 删除按钮点击事件
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    <Category("自定义事件"), Description("删除按钮点击事件")>
    Public Event CellButtonDeleteClicked(ByVal sender As Object, ByVal e As EventArgsEx.DataGridViewClickEventArgsEx)
#Region "按钮事件"
    ''' <summary>
    ''' 引发CellButtonModifyClicked事件
    ''' </summary>
    ''' <param name="columnIndex"></param>
    ''' <param name="rowIndex"></param>
    ''' <param name="value"></param>
    Friend Sub OnCellButtonModifyClicked(ByVal columnIndex As Integer, ByVal rowIndex As Integer, ByVal value As Object)
        RaiseEvent CellButtonModifyClicked(Me, New EventArgsEx.DataGridViewClickEventArgsEx(columnIndex, rowIndex, value))
    End Sub
    ''' <summary>
    ''' 引发CellButtonDeleteClicked事件
    ''' </summary>
    ''' <param name="columnIndex"></param>
    ''' <param name="rowIndex"></param>
    ''' <param name="value"></param>
    Friend Sub OnCellButtonDeleteClicked(ByVal columnIndex As Integer, ByVal rowIndex As Integer, ByVal value As Object)
        RaiseEvent CellButtonDeleteClicked(Me, New EventArgsEx.DataGridViewClickEventArgsEx(columnIndex, rowIndex, value))
    End Sub
#End Region
End Class

DataGridViewButtonColumnEx:

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Windows.Forms
Imports System.Drawing
Imports System.ComponentModel
Imports System.Windows.Forms.VisualStyles

    Public Class DataGridViewButtonColumnEx
        Inherits DataGridViewColumn

        Shared DefaultButtonSize As Size = New Size(35, 24)
        Private _ButtonSize As Size = DefaultButtonSize
        ''' <summary>
        ''' 按钮大小模板Size
        ''' </summary>
        ''' <returns></returns>
        <Category("zyjq"), Browsable(True), Localizable(True), Description("按钮大小模板。")>
        Public Property ButtonSize As Size
            Get
                Return _ButtonSize
            End Get
            Set(ByVal value As Size)
                _ButtonSize = value
            End Set
        End Property

        Shared ReadOnly DefaultButtonBack As Color = Color.Gainsboro
        ''' <summary>
        ''' 鼠标移到按钮时的背景色
        ''' </summary>
        ''' <returns></returns>
        <Category("zyjq"), Browsable(True), Localizable(True), Description("按钮背景色")>
        Public Property ButtonBack As Color = DefaultButtonBack

        Shared ReadOnly DefaultButtonTextDownColor As Color = Color.Red
        ''' <summary>
        ''' 按钮按下时文本色
        ''' </summary>
        ''' <returns></returns>
        <Category("zyjq"), Browsable(True), Localizable(True), Description("按钮按下时文本色")>
        Public Property ButtonTextDownColor As Color = DefaultButtonTextDownColor

        Shared ReadOnly DefaultButtonTextFace As Color = Color.Blue
        ''' <summary>
        ''' 默认按钮文本色
        ''' </summary>
        ''' <returns></returns>
        <Category("zyjq"), Browsable(True), Localizable(True), Description("按钮文本前景色")>
        Public Property ButtonTextFace As Color = DefaultButtonTextFace
        Shared ReadOnly DefaultButtonSpacingWidth As Int32 = 3
        Private _ButtonSpacingWidth As Int32 = DefaultButtonSpacingWidth
        ''' <summary>
        ''' 按钮间距
        ''' </summary>
        ''' <returns></returns>
        <Category("zyjq"), Browsable(True), Localizable(True), Description("按钮间距")>
        Public Property ButtonSpacingWidth As Int32
            Get
                Return _ButtonSpacingWidth
            End Get
            Set(value As Int32)
                If value > 0 Then
                    _ButtonSpacingWidth = value
                End If
            End Set
        End Property
        ''' <summary>
        ''' 修改按钮文本
        ''' </summary>
        ''' <returns></returns>
        <Category("zyjq"), Browsable(True), Localizable(True), Description("修改按钮文本")>
        Public Property ButtonModifyText As String = "修改"
        ''' <summary>
        ''' 删除按钮文本
        ''' </summary>
        ''' <returns></returns>
        <Category("zyjq"), Browsable(True), Localizable(True), Description("删除按钮文本")>
        Public Property ButtonDeleteText As String = "删除"

        Public Overrides Function Clone() As Object
            Dim column As DataGridViewButtonTwoColumnEx = CType(MyBase.Clone(), DataGridViewButtonTwoColumnEx)
            column.ButtonModifyText = ButtonModifyText
            column.ButtonDeleteText = ButtonDeleteText
            Return column
        End Function

        Public Sub New()
            MyBase.New()
            Me.CellTemplate = New DataGridViewButtonTwoCellEx()
            Me.HeaderText = "操作"
            Me.MinimumWidth = DefaultButtonSize.Width * 2 + DefaultButtonSpacingWidth * 3
        End Sub
    End Class

DataGridViewButtonCellEx:

Imports System.Windows.Forms
Imports System.Drawing
Imports System.ComponentModel
Imports System.Windows.Forms.VisualStyles

    Public Class DataGridViewButtonCellEx
        Inherits DataGridViewButtonCell
        ''' <summary>
        ''' 按键类型枚举
        ''' </summary>
        Public Enum ButtonType
            ''' <summary>
            ''' 修改按钮
            ''' </summary>
            ButtonModify = 1
            ''' <summary>
            ''' 删除按钮
            ''' </summary>
            ButtonDelete = 2
        End Enum
        ''' <summary>
        ''' 按钮状态枚举
        ''' </summary>
        Public Enum ButtonState
            ''' <summary>
            ''' 默认状态
            ''' </summary>
            ButtonDefault = 1
            ''' <summary>
            ''' 热状态
            ''' </summary>
            ButtonHot = 2
            ''' <summary>
            ''' 鼠标按下状态
            ''' </summary>
            ButtonDown = 3
        End Enum
        <Category("Jonson Design"), Browsable(True), Localizable(True), Description("所属列")>
        Public ReadOnly Property OwningColumnEx As DataGridViewButtonTwoColumnEx
            Get
                Return TryCast(Me.OwningColumn, DataGridViewButtonTwoColumnEx)
            End Get
        End Property

        <Category("Jonson Design"), Browsable(True), Localizable(True), Description("所属表格")>
        Public ReadOnly Property DataGridViewEx As DataGridViewEx
            Get
                Return TryCast(Me.DataGridView, DataGridViewEx)
            End Get
        End Property

        '修改按钮状态标志
        Private m_ButtonModifyState As ButtonState = ButtonState.ButtonDefault
        '删除按钮状态标志
        Private m_ButtonDeleteState As ButtonState = ButtonState.ButtonDefault

        Protected Overrides Sub Paint(ByVal graphics As Graphics,
                                      ByVal clipBounds As Rectangle,
                                      ByVal cellBounds As Rectangle,
                                      ByVal rowIndex As Integer,
                                      ByVal elementState 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)
            '是否需要重绘单元格的背景颜色
            'm_brushCellBack = If(Me.DataGridView.SelectedCells.Contains(Me), New SolidBrush(cellStyle.SelectionBackColor), New SolidBrush(cellStyle.BackColor))
            '单元格背景色
            Dim brushCellBack As Brush = New SolidBrush(cellStyle.BackColor)
            graphics.FillRectangle(brushCellBack, cellBounds.X, cellBounds.Y, cellBounds.Width, cellBounds.Height)

            '绘制Modify按钮
            Me.InternalDrawButton(graphics, cellBounds, OwningColumnEx.ButtonModifyText, ButtonType.ButtonModify, m_ButtonModifyState)
            '绘制Delete按钮
            Me.InternalDrawButton(graphics, cellBounds, OwningColumnEx.ButtonDeleteText, ButtonType.ButtonDelete, m_ButtonDeleteState)

            '填充单元格的边框
            MyBase.PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle)
        End Sub

        ''' <summary>
        ''' 绘制按钮
        ''' </summary>
        ''' <param name="graphics"></param>
        ''' <param name="cellBounds"></param>
        ''' <param name="buttonType">按钮类型枚举</param>
        ''' <param name="buttonState">按钮状态枚举</param>
        Protected Sub InternalDrawButton(ByVal graphics As Graphics,
                                         ByVal cellBounds As Rectangle,
                                         ByVal buttonText As String,
                                         ByVal buttonType As ButtonType,
                                         ByVal buttonState As ButtonState)
            ' 当前按钮位置大小
            Dim absBtnRegion As Rectangle = Rectangle.Empty
            '按钮背景色画笔
            Dim solidBrushButton As SolidBrush = New SolidBrush(OwningColumnEx.ButtonBack)

            ' 当前按钮绝对位置大小
            Dim buttonRegion As Rectangle = RectangleCommon.GetSmallRectOfRectangle(cellBounds, OwningColumnEx.ButtonSize, OwningColumnEx.ButtonSpacingWidth, buttonType, absBtnRegion)
            '单元格列宽太小则不绘制
            If Not cellBounds.Contains(buttonRegion.X + buttonRegion.Width, buttonRegion.Y) Then Return

            '绘制按钮
            Select Case buttonState
                Case ButtonState.ButtonHot
                    graphics.FillRectangle(solidBrushButton, buttonRegion)
                    TextRenderer.DrawText(graphics, buttonText, Me.DataGridView.Font, buttonRegion, OwningColumnEx.ButtonTextFace)
                Case ButtonState.ButtonDown
                    graphics.FillRectangle(solidBrushButton, buttonRegion)
                    TextRenderer.DrawText(graphics, buttonText, Me.DataGridView.Font, buttonRegion, OwningColumnEx.ButtonTextDownColor)
                Case Else
                    TextRenderer.DrawText(graphics, buttonText, Me.DataGridView.Font, buttonRegion, OwningColumnEx.ButtonTextFace)
            End Select
        End Sub

        Protected Overrides Sub OnMouseMove(ByVal e As DataGridViewCellMouseEventArgs)
            MyBase.OnMouseMove(e)

            If IsInRegion(e.Location, ButtonType.ButtonModify, e.ColumnIndex, e.RowIndex) Then
                m_ButtonModifyState = ButtonState.ButtonHot
                m_ButtonDeleteState = ButtonState.ButtonDefault
                Me.DataGridView.Cursor = Cursors.Hand
            ElseIf IsInRegion(e.Location, ButtonType.ButtonDelete, e.ColumnIndex, e.RowIndex) Then
                m_ButtonModifyState = ButtonState.ButtonDefault
                m_ButtonDeleteState = ButtonState.ButtonHot
                Me.DataGridView.Cursor = Cursors.Hand
            Else
                m_ButtonModifyState = ButtonState.ButtonDefault
                m_ButtonDeleteState = ButtonState.ButtonDefault
                Me.DataGridView.Cursor = Cursors.Default
            End If

            Me.DataGridView.InvalidateCell(Me)
        End Sub

        Protected Overrides Sub OnMouseLeave(ByVal rowIndex As Integer)
            MyBase.OnMouseLeave(rowIndex)
            m_ButtonModifyState = ButtonState.ButtonDefault
            m_ButtonDeleteState = ButtonState.ButtonDefault
            Me.DataGridView.Cursor = Cursors.Default
            Me.DataGridView.InvalidateCell(Me)
        End Sub

        Protected Overrides Sub OnMouseDown(ByVal e As DataGridViewCellMouseEventArgs)
            MyBase.OnMouseDown(e)

            If IsInRegion(e.Location, ButtonType.ButtonModify, e.ColumnIndex, e.RowIndex) Then
                m_ButtonModifyState = ButtonState.ButtonDown
                m_ButtonDeleteState = ButtonState.ButtonDefault
                Me.DataGridView.Cursor = Cursors.Hand
            ElseIf IsInRegion(e.Location, ButtonType.ButtonDelete, e.ColumnIndex, e.RowIndex) Then
                m_ButtonModifyState = ButtonState.ButtonDefault
                m_ButtonDeleteState = ButtonState.ButtonDown
                Me.DataGridView.Cursor = Cursors.Hand
            Else
                m_ButtonModifyState = ButtonState.ButtonDefault
                m_ButtonDeleteState = ButtonState.ButtonDefault
                Me.DataGridView.Cursor = Cursors.Default
            End If

            Me.DataGridView.InvalidateCell(Me)
        End Sub

        Protected Overrides Sub OnMouseClick(ByVal e As DataGridViewCellMouseEventArgs)
            MyBase.OnMouseClick(e)

            If e.Button = MouseButtons.Left Then
                If Me.DataGridViewEx IsNot Nothing Then
                    If IsInRegion(e.Location, ButtonType.ButtonModify, e.ColumnIndex, e.RowIndex) Then
                        Me.DataGridViewEx.OnCellButtonModifyClicked(e.ColumnIndex, e.RowIndex, Me.Value)
                    ElseIf IsInRegion(e.Location, ButtonType.ButtonDelete, e.ColumnIndex, e.RowIndex) Then
                        Me.DataGridViewEx.OnCellButtonDeleteClicked(e.ColumnIndex, e.RowIndex, Me.Value)
                    End If
                End If
            End If
        End Sub

        Protected Function IsInRegion(ByVal p As Point, ByVal buttonType As ButtonType, ByVal columnIndex As Integer, ByVal rowIndex As Integer) As Boolean
            Dim cellBounds As Rectangle = DataGridView(columnIndex, rowIndex).ContentBounds
            Dim absBtnRegion As Rectangle = Rectangle.Empty
            RectangleCommon.GetSmallRectOfRectangle(cellBounds, OwningColumnEx.ButtonSize, OwningColumnEx.ButtonSpacingWidth, buttonType, absBtnRegion)
            Return absBtnRegion.Contains(p)
        End Function
    End Class

获取按钮位置:

Public Class RectangleCommon
         ''' <summary>
        ''' 获取在大的Rectangle中的小矩形
        ''' </summary>
        ''' <param name="rectangle">单元格Rectangle</param>
        ''' <param name="smallSize">绘制按钮的Size</param>
        ''' <param name="SpacingWidth">两按钮的间距</param>
        ''' <param name="buttonType">按钮类型</param>
        ''' <param name="absRectangle">输出的按钮相对单元格的Rectangle</param>
        ''' <returns>返回按钮的绝对Rectangle</returns>
        Public Shared Function GetSmallRectOfRectangle(ByVal rectangle As Rectangle, ByVal smallSize As Size, ByVal SpacingWidth As Int32, ByVal buttonType As Int32, ByRef absRectangle As Rectangle) As Rectangle
            Dim rect As Rectangle = New Rectangle()
            absRectangle = New Rectangle()
            absRectangle.Size = smallSize
            absRectangle.X = SpacingWidth + (SpacingWidth + smallSize.Width) * (buttonType - 1)
            absRectangle.Y = (rectangle.Height - smallSize.Height) \ 2
            rect.Size = smallSize
            rect.X = absRectangle.X + rectangle.X
            rect.Y = absRectangle.Y + rectangle.Y
            Return rect
        End Function
    End Class

单击链接单元格内容事件数据:

    Public Class DataGridViewClickEventArgsEx
        Inherits EventArgs
        Public Property ColumnIndex As Integer
        Public Property RowIndex As Integer
        Public Property Value As Object

        Public Sub New(ByVal columnIndex As Integer, ByVal rowIndex As Integer, ByVal value As Object)
            Me.ColumnIndex = columnIndex
            Me.RowIndex = rowIndex
            Me.Value = value
        End Sub
    End Class
已标记关键词 清除标记
相关推荐
*调整导出及打印的格式与显示一致;合计行,详细参见第10条修正功能,全部源码及示例。 * 文 件 名:DataGridViewEx.cs * 创 建 人:明振居士 * Email:nzj.163@163.com qq:342155124 * 创建时间:2010-06-01 * 最后修改时间:2012-1-19 增加第10条所示的功能;修改头超过26的错误,导出excel为数组方式,速度更快,导出的单元格设置为文本格式。 * 标 题:用户自定义的DataGridView控件 * 功能描述:扩展DataGridView控件功能 * 扩展功能: * 1、搜索Search(); 有两个同明方法,参数不同 F3为快捷键继续向下搜索 * 2、用TreeView HeadSource 来设置复杂的标题样式,如果某个节点对应的显示隐藏,请将该节点Tag设置为hide,隐藏的排位置与绑定数据元位置对应,树叶节点的顺序需要与结果集的顺序一致 * 3、通过反射导出Excel,无需引用com组件,方法ExportExcel() ,不受数的限制,表头同样可以导出,AutoFit属性设置导出excel后是否自动调整单元格宽度 * 导出内容支持自定义的:Title List Header List Footer,支持在设计时值的设定,窗口关闭时Excel资源自动彻底释放 * 4、可以自己任意设定那些显示及不显示,通过调用方法SetColumnVisible()实现。 * 5、设置标题SetHeader(),设置永远可见AlwaysShowCols(),设置暂时不可见HideCols() * 注意,当使用了TreeView作为复杂Header时,不要使用本方法,Header显示的内容根据treeview内容而显示 * 6、宽度及顺序的保存SaveGridView(),加载LoadGridView() * 7、支持所见即所得的打印功能,举例如下 * private void button5_Click(object sender, EventArgs e) { DGVPrinter printer = new DGVPrinter(); printer.PrintPreviewDataGridView(DataGridViewEx1); } * 8、自定义合并行与,行合并用 MergeRowColumn 属性,合并用MergeColumnNames属性,都可以定义多个 * 9、行标号的设置 bool ShowRowNumber; * 10、增加最后一行的汇总行,支持的聚合函数,参见http://msdn.microsoft.com/zh-cn/library/system.data.datacolumn.[removed]v=VS.100).aspx * 假设对id显示“合计”字符,avgPrice进行平均值,total显示合计,则对ComputeColumns增加三行内容:id,合计:;avgPrice,Avg(avgPrice);total,Sum(total) * 如果需要对值进行格式控制,请实现beforeShow事件 * 增加了导出和打印对应的支持,所见即所得的对齐方应用于式导出及打印。
开发环境为vs2012 C#源码及完全样例 此版本为2012.2.24日更新版本,更新内容为 * 最后修改时间:2012.2.24 增加了汇总信息的自定义控制属性,参见功能描述12 * 2012.2.23 修改了过多时父标题不显示的问题,重新写了算法,修改了标题头重叠及不能换行的问题,参见说明11. 总功能举如下: /**************************************************************************************************** * Copyright (C) 2012 明振居士 版权没有,任意拷贝及使用,但对使用造成的任何后果不负任何责任,互相开源影响,共同进步 * 文 件 名:DataGridViewEx.cs * 创 建 人:明振居士 * Email:nzj.163@163.com qq:342155124 * 创建时间:2010-06-01 * 最后修改时间:2012.2.24 增加了汇总信息的自定义控制属性,参见功能描述12 * 2012.2.23 修改了过多时父标题不显示的问题,重新写了算法,修改了标题头重叠及不能换行的问题,参见说明11. * 2012-1-19 增加第10条所示的功能;修改头超过26的错误,导出excel为数组方式,速度更快,导出的单元格设置为文本格式。 * 标 题:用户自定义的DataGridView控件 * 功能描述:扩展DataGridView控件功能 * 扩展功能: * 1、搜索Search(); 有两个同明方法,参数不同 F3为快捷键继续向下搜索 * 2、用TreeView HeadSource 来设置复杂的标题样式,如果某个节点对应的显示隐藏,请将该节点Tag设置为hide,隐藏的排位置与绑定数据元位置对应,树叶节点的顺序需要与结果集的顺序一致 * 3、通过反射导出Excel,无需引用com组件,方法ExportExcel() ,不受数的限制,表头同样可以导出,AutoFit属性设置导出excel后是否自动调整单元格宽度 * 导出内容支持自定义的:Title List<string> Header List<string> Footer,支持在设计时值的设定,窗口关闭时Excel资源自动彻底释放 * 4、可以自己任意设定那些显示及不显示,通过调用方法SetColumnVisible()实现。 * 5、设置标题SetHeader(),设置永远可见AlwaysShowCols(),设置暂时不可见HideCols() * 注意,当使用了TreeView作为复杂Header时,不要使用本方法,Header显示的内容根据treeview内容而显示 * 6、宽度及顺序的保存SaveGridView(),加载LoadGridView() * 7、支持所见即所得的打印功能,举例如下 * private void button5_Click(object sender, EventArgs e) { DGVPrinter printer = new DGVPrinter(); printer.PrintPreviewDataGridView(DataGridViewEx1); } * 8、自定义合并行与,行合并用 MergeRowColumn 属性,合并用MergeColumnNames属性,都可以定义多个 * 9、行标号的设置 bool ShowRowNumber; * 10、增加最后一行的汇总行,支持的聚合函数,参见http://msdn.microsoft.com/zh-cn/library/system.data.datacolumn.[removed]v=VS.100).aspx * 假设对id显示“合计”字符,avgPrice进行平均值,total显示合计,则对ComputeColumns属性增加三行内容:id,合计:;avgPrice,Avg(avgPrice);total,Sum(total) * 如果需要对值进行格式控制,请实现beforeShow事件 * 增加了导出和打印对应的支持,所见即所得的对齐方应用于式导出及打印。 * 11、标题头自动换行,默认设置为每个标题头行高为22,如果设置的字体更大,将自动进行计算。如果需要多行显示,请根据需要调节ColumnHeaderHeight属性值, * 其估算方法为预计的标题头层数乘以22,或层数乘以设置的字体高度。 * 12、针对第10条功能,增加汇总信息的自定义控制属性,汇总字体SummaryFont,汇总字体颜色SummaryFontColor,汇总背景色SummaryBGColor,边框与整个表格边框一致 ****************************************************************************************************/
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页