How to display an image in a datagridview column header?
Solution 1
One way you can do this is to use the CellsPainting
event to draw the
bitmap for a particular header cell. Here is code that does this
assuming the bitmap is in an imagelist
.
//this.images is an ImageList with your bitmaps
void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex == 1 && e.RowIndex == -1)
{
e.PaintBackground(e.ClipBounds, false);
Point pt = e.CellBounds.Location; // where you want the bitmap in the cell
int offset = (e.CellBounds.Width - this.images.ImageSize.Width) / 2;
pt.X += offset;
pt.Y += 1;
this.images.Draw(e.Graphics, pt, 0);
e.Handled = true;
}
}
Solution 2
I needed a bit more complex thing - adding image in front of text in some column headers with respect to column alignment.
You need to implement your own System.Windows.Forms.DataGridViewColumnHeaderCell
and replace ColumnHeaderCell
:
// Create header and set up image
YourDataGridViewColumnHeaderCell headerCell = new YourDataGridViewColumnHeaderCell();
headerCell.Image = something;
// Create column
DataGridViewColumn yourColumn = new DataGridViewTextBoxColumn();
// ...
yourColumn.ColumnHeaderCell = new headerCell;
Now the funny part (implementation of your column header):
class YourDataGridViewColumnHeaderCell : System.Windows.Forms.DataGridViewColumnHeaderCell
{
// Set up image as you want
System.Drawing.Image Image { get; set; }
}
Now we want to add Paint()
method. The only tricky part is working with System.Windows.Forms.DataGridViewPaintParts
.
protected override void Paint( Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates dataGridViewElementState,
object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts )
{
// Outside header or without an image, use default painting
if ((rowIndex != -1) || (Image == null)) {
base.Paint( graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts );
return;
}
// Borders, background, focus selection can remain the same
// But Foreground will have different image
base.Paint( graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, value, formattedValue, errorText, cellStyle,
advancedBorderStyle, paintParts & ~DataGridViewPaintParts.ContentForeground );
// Repainting of content background (that's where we want to place our image)
if ((paintParts & DataGridViewPaintParts.ContentBackground) != DataGridViewPaintParts.None) {
// +4 is hardcoded margin
Point bounds = new Point( cellBounds.X + 4, cellBounds.Y );
// Handle vertical alignment correctly
switch (cellStyle.Alignment) {
// Top
case DataGridViewContentAlignment.TopLeft:
case DataGridViewContentAlignment.TopCenter:
case DataGridViewContentAlignment.TopRight:
// Already set
break;
// Middle
case DataGridViewContentAlignment.MiddleLeft:
case DataGridViewContentAlignment.MiddleCenter:
case DataGridViewContentAlignment.MiddleRight:
bounds.Y = cellBounds.Y + (cellBounds.Height - Image.Height) / 2;
break;
// Bottom
case DataGridViewContentAlignment.BottomLeft:
case DataGridViewContentAlignment.BottomCenter:
case DataGridViewContentAlignment.BottomRight:
bounds.Y = cellBounds.Y + (cellBounds.Height - Image.Height);
break;
}
graphics.DrawImage( Image, bounds );
}
// Foreground should be shifted by left image margin + image.width + right
// image margin and of course target spot should be a bit smaller
if ((paintParts & DataGridViewPaintParts.ContentForeground) != DataGridViewPaintParts.None) {
Rectangle newCellBounds = new Rectangle( cellBounds.X + 4 + Image.Width + 4, cellBounds.Y, cellBounds.Width - Image.Width - 8, cellBounds.Height );
base.Paint( graphics, clipBounds, newCellBounds, rowIndex, dataGridViewElementState, value, formattedValue, errorText, cellStyle,
advancedBorderStyle, DataGridViewPaintParts.ContentForeground );
}
}
If you want to use AutoSizeColumnsMode
set to DataGridViewAutoSizeColumnsMode.ColumnHeaders
(so you would autofit image and text) you need to override DataGridViewColumnHeaderCell.GetPreferredSize
. I did this by using base implementation and adding Image.Width + Padding
to it.
protected override Size GetPreferredSize( Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex,Size constraintSize )
{
// Load up original image
Size original = base.GetPreferredSize( graphics, cellStyle, rowIndex, constraintSize );
// Ensure the image is set and that we are working on header
if ((rowIndex != -1) || (Image == null)) {
return original;
}
// -1 is reserved value
if (original.Width < 0) {
return original;
}
return new Size( original.Width + Image.Width + 4, original.Height );
}
NOTE: I've spent several hours digging in .NET sources until I figured this out. Hopefully you won't have to.
Solution 3
Try This:
Private Sub DataGridView1_CellPainting(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles DataGridView1.CellPainting
If e.RowIndex > -1 Then
If e.ColumnIndex = -1 Then
e.Paint(e.CellBounds, DataGridViewPaintParts.Focus And Not DataGridViewPaintParts.ContentForeground)
DataGridView1.RowHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single
e.Graphics.DrawImage(IconImg, e.CellBounds)
e.Handled = True
'DataGridView1.RowHeadersWidth = 100
'DataGridView1.ColumnHeadersHeight = 25
End If
End If
Admin
Updated on August 12, 2022Comments
-
Admin almost 2 years
At run-time, I am adding a
DataGridView
to a windows form. The final column is aDataGridViewImageColumn
:Dim InfoIconColumn As New DataGridViewImageColumn MyDataGridView.Columns.Insert(MyDataGridView.Columns.Count, InfoIconColumn)
Adding the following code will get my Information Icon (bitmap) to display in each of the column cells but NOT the column header:
Dim InfoIcon As New Bitmap("C:\MyPath\InfoIcon.bmp") InfoIconColumn.Image = InfoIcon
Also, it is worth noting that the image displays 'perfectly' in the cells i.e. it is sized correctly to fit the cell.
However, I cannot find a way to add the same image to the column header cell. After some googling I used the following code which placed the image in the header cell but left me with two problems:
- The image did not 'auto-size' to the column headercell in the same way it did when added to the column cells. The image was slightly larger and blurred.
- By using the
_CellPainting
event slowed down performance i.e. when hovering over theDataGridView
to highlight the selected row the highlighting lagged behind where my mouse was placed.
Here is the code:
Private Sub MyDataGridView_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles MyDataGridView.CellPainting Dim InfoIcon As Image = Image.FromFile("C:\MyPath\InfoIcon.bmp") If e.RowIndex = -1 AndAlso e.ColumnIndex = MyDataGridView.Columns.Count - 1 Then e.Paint(e.CellBounds, DataGridViewPaintParts.All And Not DataGridViewPaintParts.ContentForeground) e.Graphics.DrawImage(InfoIcon, e.CellBounds) e.Handled = True End If End Sub
Does anybody know of a way to solve my problem and get a nicely sized, sharp image into a
DataGridViewImageColumn
headercell at run-time? -
RJ Lohan about 12 yearsIn the event you don't store the Image in an ImageList, modifying the 2nd last LOC to; e.Graphics.DrawImage(image, pt); also works.
-
Khurram Ali about 9 yearsCan we add panel control just above the
datagridview column headers
? -
Vyktor about 9 years@KhurramAli I've never tested/tried that... I think it should be possible... If you get to test it, please let me know whether it worked.
-
Jack almost 9 yearsIt works but how can I place the image by text's side with some padding?
-
ehh about 6 yearsYou should explain what you are doing. I was lucky that I tried your code since e.Paint(e.CellBounds, DataGridViewPaintParts.Focus And Not DataGridViewPaintParts.ContentForeground) was exactly what I was looking for.
-
user3700562 almost 6 years@Vyktor DataGridViewColumn has no such property ColumnHeaderCell. Can you clarify?
-
Vyktor almost 6 years@user3700562 according to
DataGridViewColumn
theHeaderCell
is Available since 2.0. But it also notes that it's[BrowsableAttribute(false)]
so you are NOT able to see it in designer (but have to change it programmatically).