Tutorial :How to display an image in a datagridview column header?



Question:

At run-time, I am adding a DataGridView to a windows form. The final column is a DataGridViewImageColumn:

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:

  1. 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.
  2. By using the _CellPainting event slowed down performance i.e. when hovering over the DataGridView 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?


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  


Solution:4

try this code:

    Private Sub DataGridView1_CellPainting(ByVal sender As System.Object, _              ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) _              Handles DataGridView1.CellPainting          If e.RowIndex = -1 AndAlso e.ColumnIndex = DataGridView1.Columns.Count - 1 Then              e.Paint(e.CellBounds, DataGridViewPaintParts.All And Not DataGridViewPaintParts.ContentForeground)              e.Graphics.DrawImage(IconImg, e.CellBounds)              e.Handled = True          End If      End Sub  

if you have read full article for doing this check This link:

http://www.authorcode.com/add-image-on-datagridview-column-header-in-vb-net/


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »