2009-07-28 85 views
6

En tiempo de ejecución, estoy agregando un DataGridView a un formulario de Windows. La última columna es un DataGridViewImageColumn:¿Cómo mostrar una imagen en un encabezado de columna de Datagridview?

Dim InfoIconColumn As New DataGridViewImageColumn 
MyDataGridView.Columns.Insert(MyDataGridView.Columns.Count, InfoIconColumn) 

añadiendo el siguiente código será conseguir mi icono de información (mapa de bits) para mostrar en cada una de las celdas de la columna, pero no el encabezado de la columna:

Dim InfoIcon As New Bitmap("C:\MyPath\InfoIcon.bmp") 
InfoIconColumn.Image = InfoIcon 

Además, Vale la pena señalar que la imagen se muestra "perfectamente" en las celdas, es decir, tiene el tamaño correcto para adaptarse a la celda.

Sin embargo, no puedo encontrar la forma de agregar la misma imagen a la celda del encabezado de la columna. Después de algunos googlear he utilizado el siguiente código que coloca la imagen en la celda de encabezado, pero me dejó con dos problemas:

  1. La imagen no se 'auto-size' a la headercell la columna de la misma manera que lo hizo cuando se añade a las celdas de la columna. La imagen era un poco más grande y borrosa.
  2. Al utilizar el evento _CellPainting se ralentizó el rendimiento, es decir, al pasar el puntero sobre DataGridView para resaltar la fila seleccionada, el resaltado quedó rezagado detrás de donde se colocó mi mouse.

Aquí está el código:

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 

¿Alguien sabe de una manera de resolver mi problema y obtener una imagen de buen tamaño, agudo en un headercell DataGridViewImageColumn en tiempo de ejecución?

Respuesta

15

Una manera de hacer esto es usar el evento CellsPainting para dibujar el mapa de bits para una celda de encabezado en particular. Aquí está el código que hace esto suponiendo que el mapa de bits está en un 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; 
    } 
} 
+0

@Lucas - Gracias por el consejo. Daré esta tratar e informar ... –

+2

En el caso de que no almacenar la imagen en una ImageList, la modificación de la segunda pasada a LOC; e.Graphics.DrawImage (imagen, pt); también funciona –

+0

Funciona, pero ¿cómo puedo colocar la imagen por el lado del texto con algo de relleno? – Jack

0

prueba este código:

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 

si ha leído el artículo completo para realizar esta comprobación Este enlace:

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

2

que necesitaba un poco más complejo cosa - imagen añadiendo delante del texto en algunos encabezados de columna con respecto a la alineación de columnas.

que necesita para implementar su propio System.Windows.Forms.DataGridViewColumnHeaderCell y reemplazar ColumnHeaderCell:

// Create header and set up image 
YourDataGridViewColumnHeaderCell headerCell = new YourDataGridViewColumnHeaderCell(); 
headerCell.Image = something; 

// Create column 
DataGridViewColumn yourColumn = new DataGridViewTextBoxColumn(); 
// ... 
yourColumn.ColumnHeaderCell = new headerCell; 

Ahora la parte divertida (aplicación de la cabecera de la columna):

class YourDataGridViewColumnHeaderCell : System.Windows.Forms.DataGridViewColumnHeaderCell 
{ 
    // Set up image as you want 
    System.Drawing.Image Image { get; set; } 
} 

Ahora queremos añadir Paint() método. La única parte difícil es trabajar con 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); 
    } 

} 

Si desea utilizar AutoSizeColumnsMode conjunto de DataGridViewAutoSizeColumnsMode.ColumnHeaders (lo que sería Autofit imagen y texto) que necesita para anular DataGridViewColumnHeaderCell.GetPreferredSize. Hice esto mediante el uso de la implementación base y agregando Image.Width + Padding a ella.

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); 
} 

NOTA: he pasado varias horas cavando en .NET sources hasta que me di cuenta de esto. Espero que no sea necesario.

+0

¿Se puede agregar el control del panel justo encima de los '' encabezados de la columna 'datagridview'? –

+0

@KhurramAli nunca he probado/intentado que ... creo que debería ser posible ... Si se llega a probar que, por favor, hágamelo saber si funcionó. – Vyktor

0

intenta esto:

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 
Cuestiones relacionadas