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
相关产品推荐
相关产品推荐

