1

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()

Smarton
  • 94
  • 1
  • 10
  • Post te code you're using to generate your DataGridView and the nature of its DataSource. Since you can create a new `DataGridViewTextBoxColumn`, you can also create a new `DataGridViewImageColumn`, the initialization method doesn't change (for a default object). Btw, when you generate Images from the Resources, assign the Images to Bitmap objects then assign a Bitmap to a Control's property. Dispose of these Bitmap objects when not needed anymore (when you change a Control's Property or the Parent Form closes). – Jimi Dec 08 '19 at 08:30
  • Addition to Jimi's comment, when you create the new `DataGridViewImageColumn`, set it's `DefaultCellStyle.NullValue = Nothing`, and handle the `RowsAdded` event of the `DGV` to set the required image for each row. Also if you want to get rid of the last row's default `null` image, in the same event, check `If e.RowIndex = 0 Then` ... set the value of the image cell to `Nothing`. Good luck. –  Dec 08 '19 at 11:09
  • @JQSOFT Well, you can set the `DataGridViewImageColumn.CellTemplate` using a custom `DataGridViewImageCell`, where you override `DefaultNewRowValue`, setting it to `new Bitmap(1,1)` (or a custom Bitmap of choice, of course) in the `DataGridViewImageCell` constructor (since it's a getter-only property). – Jimi Dec 08 '19 at 11:53
  • @Jimi True true, I'd use this approach. –  Dec 08 '19 at 12:16
  • 1
    I have edited the question to show the code as requested – Smarton Dec 08 '19 at 12:36
  • 1
    **Please note:** instead of displaying the required image (picture / picture1) which is based on a condition , it writes ```System.Drawing.Bitmap``` in the cell. – Smarton Dec 08 '19 at 12:43

1 Answers1

1

If you are getting something like:

Q59232259-1

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, its 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 From.Closing event:

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

and you will get something like:

Q59232259-2

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()
  • 1
    Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/203932/discussion-on-answer-by-jqsoft-image-not-displaying-in-datagridview-column-in-vb). – Samuel Liew Dec 09 '19 at 18:49