Search code examples
.netvb.netwinformsdatagridviewdatagridviewimagecolumn

Image not displaying in datagridview column in vb.net


I have the following code that I want to use to display an image in a DataGridView cell:

dgvInventory.Item(7, i).Value = My.Resources.ResourceManager.GetObject("picture")

But instead of displaying the required image, it shows System.Drawing.Bitmap in the cell.

Please note that the DataGridView table was created at run time, so I know I am supposed to change the column property to be an DataGridViewImageColumn but I just could not figure out how to.

Thanks in advance

Please I really need help with this.

Below is the Complete code

con.Open()
tables.Clear()
dgvInventory.DataSource = tables
dgvInventory.DataSource = Nothing

sql = "SELECT ItemID, itemname, status, ''  FROM [" & InventoryTable & "]"
da = New OleDb.OleDbDataAdapter(sql, con)
da.Fill(ds, InventoryTable)
con.Close() 

'This Loads Records into DataGrid
Dim view As New DataView(tables(0))
source1.DataSource = view
dgvInventory.DataSource = view
dgvInventory.AllowUserToAddRows = False

For i = 0 To dgvInventory.RowCount - 1
   If dgvInventory.Item(2, i).Value = 1 then
     dgvInventory.Item(3, i).Value = My.Resources.ResourceManager.GetObject("picture")
   Else
     dgvInventory.Item(3, i).Value = My.Resources.ResourceManager.GetObject("picture1")
   End If
Next

dgvInventory.Columns(0).HeaderText = "ID"
dgvInventory.Columns(1).HeaderText = "Item / Product / Service"
dgvInventory.Columns(2).HeaderText = "Status"
dgvInventory.Columns(3).HeaderText = "Icon"

dgvInventory.Columns(0).Width = 100
dgvInventory.Columns(1).Width = 300
dgvInventory.Columns(2).Width = 100
dgvInventory.Columns(3).Width = 100

dgvInventory.ClearSelection()


Solution

  • If you are getting something like:

    DataGridView with one of the columns having the text Syste.Drawing.Bitmap in each row

    That's because you are getting what the ToString function returns for an instance of a Bitmap type to be displayed in a default DataGridViewTextBoxCell. Note that the icon is not a part of your DataTable, it's just an image from your resources.

    Instead, add a new DataGridViewImageColumn after setting the DataSource property of the DGV. Please consider the following example:

    'Class level variables
    Private bmp1 As New Bitmap(My.Resources.picture)
    Private bmp2 As New Bitmap(My.Resources.picture1)
    

    In a method that calls and displays the data, replace this with your actual data source.

    Dim dt As New DataTable
    dt.Columns.Add(New DataColumn("ID"))
    dt.Columns.Add(New DataColumn("Item"))
    dt.Columns.Add(New DataColumn("Status"))
    
    For i As Integer = 1 To 10
        dt.Rows.Add(i, $"Item {i}", $"Status {i}")
    Next
    
    With dgvInventory
        .Clear()
        .DataSource = Nothing
        .DataSource = dt
        .Columns("Item").HeaderText = "Item / Product / Service"
    End With
    
    Dim imageColIndex As Integer = dgvInventory.Columns.Count
    Dim imgCol As New DataGridViewImageColumn(False) With {
        .CellTemplate = New DataGridViewImageCell() With {
            .Style = New DataGridViewCellStyle() With {
                .Alignment = DataGridViewContentAlignment.MiddleCenter
            }
        },
        .DisplayIndex = imageColIndex,
        .Image = Nothing,
        .Name = "Image",
        .HeaderText = "Image",
        .Width = CInt(dgvInventory.RowTemplate.Height * 1.5),
        .DefaultCellStyle = New DataGridViewCellStyle() With {.NullValue = Nothing}
    }
    
    AddHandler dgvInventory.CellFormatting,
        Sub(obj, arg)
            If arg.ColumnIndex = imageColIndex Then
                arg.Value = If(arg.RowIndex Mod 2 = 0, bmp1, bmp2)
            End If
        End Sub
    
    dgvInventory.Columns.Insert(imageColIndex, imgCol)
    

    Where imageColIndex is the index of the image column.

    Don't forget to clean up in the Form.Closing event:

    bmp1?.Dispose()
    bmp2?.Dispose()
    

    and you will get something like:

    DataGridView with one of the columns showing an appropriate icon in each row

    Note that you don't need to add columns at design time: you can edit the columns' properties after binding a DataTable, DataView, BindingSource, etc., to your DGV.

    Implementing that in your code:

    tables.Clear()
    con.Open()
    sql = "SELECT ItemID, itemname, status, ''  FROM [" & InventoryTable & "]"
    da = New OleDb.OleDbDataAdapter(sql, con)
    da.Fill(ds, InventoryTable)
    con.Close()
    con.Dispose()
    
    Dim view As New DataView(tables(0))
    source1.DataSource = view
    
    With dgvInventory
        .Columns.Clear()
        .DataSource = Nothing
        .DataSource = view
        .Columns(0).HeaderText = "ID"
        .Columns(0).Width = 100
        .Columns(1).HeaderText = "Item / Product / Service"
        .Columns(1).Width = 300
        .Columns(2).HeaderText = "Status"
        .Columns(2).Width = 100
    End With
    
    Dim imageColIndex As Integer = dgvInventory.Columns.Count
    Dim imgCol As New DataGridViewImageColumn(False) With {
        .CellTemplate = New DataGridViewImageCell() With {
        .Style = New DataGridViewCellStyle() With {
        .Alignment = DataGridViewContentAlignment.MiddleCenter
    }
    },
    .DisplayIndex = imageColIndex,
    .Image = Nothing,
    .Name = "Icon",
    .HeaderText = "Icon",
    .Width = CInt(dgvInventory.RowTemplate.Height * 1.5),
    .DefaultCellStyle = New DataGridViewCellStyle() With {.NullValue = Nothing}
    }
    
    AddHandler dgvInventory.CellFormatting,
        Sub(obj, arg)
            If arg.ColumnIndex = imageColIndex Then
                Dim status As Integer = Convert.ToInt32(
                DirectCast(obj, DataGridView).Item(2, arg.RowIndex).Value)
    
                arg.Value = If(status = 1, bmp1, bmp2)
            End If
        End Sub
    
    dgvInventory.Columns.Insert(imageColIndex, imgCol)
    dgvInventory.ClearSelection()