C# 如何在 datagridview 列标题中显示图像?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1196400/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 10:36:34  来源:igfitidea点击:

How to display an image in a datagridview column header?

c#vb.netwinformsdatagridview

提问by

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

在运行时,我将 a 添加DataGridView到 Windows 窗体中。最后一列是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 _CellPaintingevent slowed down performance i.e. when hovering over the DataGridViewto highlight the selected row the highlighting lagged behind where my mouse was placed.
  1. 图像没有像添加到列单元格时那样“自动调整”到列标题单元格。图像稍大且模糊。
  2. 通过使用该_CellPainting事件会降低性能,即当悬停在 上DataGridView以突出显示所选行时,突出显示落后于我放置鼠标的位置。

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 DataGridViewImageColumnheadercell at run-time?

有没有人知道解决我的问题并DataGridViewImageColumn在运行时将尺寸合适、清晰的图像放入标题单元的方法?

回答by Kredns

One way you can do this is to use the CellsPaintingevent to draw the bitmap for a particular header cell. Here is code that does this assuming the bitmap is in an imagelist.

一种方法是使用该CellsPainting事件为特定标题单元格绘制位图。这是假设位图在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;
    }
}

回答by Herry

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/

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

回答by Vyktor

I needed a bit more complex thing - adding image in front of text in somecolumn headers with respect to column alignment.

我需要一些更复杂的东西 - 在某些列标题中的文本前面添加图像,以与列对齐相关。

You need to implement your own System.Windows.Forms.DataGridViewColumnHeaderCelland replace ColumnHeaderCell:

您需要实现自己的System.Windows.Forms.DataGridViewColumnHeaderCell并替换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.

现在我们要添加Paint()方法。唯一棘手的部分是使用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 AutoSizeColumnsModeset to DataGridViewAutoSizeColumnsMode.ColumnHeaders(so you would autofit image andtext) you need to override DataGridViewColumnHeaderCell.GetPreferredSize. I did this by using base implementation and adding Image.Width + Paddingto it.

如果你想使用AutoSizeColumnsModeset to DataGridViewAutoSizeColumnsMode.ColumnHeaders(这样你会自动调整图像文本),你需要覆盖DataGridViewColumnHeaderCell.GetPreferredSize. 我通过使用基本实现并添加Image.Width + Padding到它来做到这一点。

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 sourcesuntil I figured this out. Hopefully you won't have to.

注意:我已经花了几个小时挖掘.NET 源代码,直到我弄明白了这一点。希望你不必这样做。

回答by Mogahed Nasr

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