You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET DataGridView自定义图文列换行时图片垂直居中实现

DataGridView图文列图片垂直居中实现方案

现有实现代码

自定义图文列类代码:

Public Class DataGridViewTextAndImageColumn
    Inherits DataGridViewTextBoxColumn
    Private imageValue As Image
    Private imageSize_Renamed As Size

    Public Sub New()
        CellTemplate = New TextAndImageCell()
    End Sub

    Public Overrides Function Clone() As Object
        Dim c As DataGridViewTextAndImageColumn = TryCast(MyBase.Clone(), DataGridViewTextAndImageColumn)
        c.imageValue = imageValue
        c.imageSize_Renamed = imageSize_Renamed
        Return c
    End Function

    Public Property Image() As Image
        Get
            Return imageValue
        End Get
        Set(ByVal value As Image)
            If Image IsNot value Then
                imageValue = value
                imageSize_Renamed = value.Size

                If InheritedStyle IsNot Nothing Then
                    Dim inheritedPadding As Padding = InheritedStyle.Padding
                    DefaultCellStyle.Padding = New Padding(imageSize_Renamed.Width, inheritedPadding.Top, inheritedPadding.Right, inheritedPadding.Bottom)
                End If
            End If
        End Set
    End Property

    Friend ReadOnly Property ImageSize() As Size
        Get
            Return imageSize_Renamed
        End Get
    End Property
End Class

Public Class TextAndImageCell
    Inherits DataGridViewTextBoxCell

    Private imageValue As Image
    Private imageSize As Size

    Public Overrides Function Clone() As Object
        Dim c As TextAndImageCell = TryCast(MyBase.Clone(), TextAndImageCell)
        c.imageValue = imageValue
        c.imageSize = imageSize
        Return c
    End Function

    Public Property Image() As Image
        Get
            If OwningColumn Is Nothing OrElse Me.OwningTextAndImageColumn Is Nothing Then

                Return imageValue
            ElseIf imageValue IsNot Nothing Then
                Return imageValue
            Else
                Return OwningTextAndImageColumn.Image
            End If
        End Get
        Set(ByVal value As Image)
            If imageValue IsNot value Then
                imageValue = value
                imageSize = value.Size

                Dim inheritedPadding As Padding = InheritedStyle.Padding
                Style.Padding = New Padding(imageSize.Width, inheritedPadding.Top, inheritedPadding.Right, inheritedPadding.Bottom)
            End If
        End Set
    End Property

    Protected Overrides Sub Paint(ByVal graphics As Graphics, ByVal clipBounds As Rectangle, ByVal cellBounds As Rectangle, ByVal rowIndex As Integer, ByVal cellState 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)
        ' 绘制基础内容
        MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)

        If Image IsNot Nothing Then
            ' 绘制裁剪到单元格范围内的图片
            Dim container As Drawing2D.GraphicsContainer = graphics.BeginContainer()

            graphics.SetClip(cellBounds)
            graphics.DrawImageUnscaled(Image, cellBounds.Location)

            graphics.EndContainer(container)
        End If
    End Sub

    Private ReadOnly Property OwningTextAndImageColumn() As DataGridViewTextAndImageColumn
        Get
            Return TryCast(OwningColumn, DataGridViewTextAndImageColumn)
        End Get
    End Property
End Class

窗体配置代码:

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
             With DataGridView1
            .DefaultCellStyle.WrapMode = DataGridViewTriState.True
            .Columns(1).DefaultCellStyle.WrapMode = DataGridViewTriState.True
            .AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells
            .SelectionMode = DataGridViewSelectionMode.FullRowSelect
        End With

    End Sub
End Class

运行效果与问题

当前正常行高效果:
效果示意图
开启文本自动换行、行高自适应后,文本自动垂直居中,但图片始终停靠在单元格顶部,无法跟随行高垂直居中:
问题示意图

解决方法

问题出在TextAndImageCell的Paint事件中,绘制图片直接使用了cellBounds.Location作为绘制起点,这个坐标是单元格的左上角点,因此图片永远固定在单元格顶部。
只需要修改图片绘制的垂直坐标,根据单元格实际高度计算居中偏移量即可,替换原有Paint方法代码为以下内容:

Protected Overrides Sub Paint(ByVal graphics As Graphics, ByVal clipBounds As Rectangle, ByVal cellBounds As Rectangle, ByVal rowIndex As Integer, ByVal cellState 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)
    ' 绘制基础文本内容
    MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)

    If Image IsNot Nothing Then
        Dim container As Drawing2D.GraphicsContainer = graphics.BeginContainer()
        graphics.SetClip(cellBounds)
        ' 计算垂直居中坐标:水平保持左侧对齐适配文字padding,垂直方向算居中偏移
        Dim imgY As Integer = cellBounds.Top + cellStyle.Padding.Top + 
            ((cellBounds.Height - cellStyle.Padding.Vertical) - Image.Height) \ 2
        graphics.DrawImageUnscaled(Image, cellBounds.Left + cellStyle.Padding.Left, imgY)
        graphics.EndContainer(container)
    End If
End Sub

代码说明:

  • 计算垂直坐标时扣除了单元格上下内边距,保证图片在单元格内容区域居中,不会被padding偏移
  • 水平坐标也加了左侧padding适配,避免图片贴到单元格边框线上
  • 用整数除法\计算偏移,避免坐标出现小数导致图片发虚
    修改后无论行高随自适应怎么变化,图片都会和文本保持垂直居中对齐。

内容的提问来源于stack exchange,提问作者Lider13

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 19:21:29