2

Goal

To be able to paint rows in my DataGridViews in order to help a user better understand what is going on in the application. Take this image for an example:

  • Light red = Deleted
  • Yellow = Relationship to the Option Type Select (top left)
  • Bright Red = Deleted & Related to the Option Type Selected (top left)

Color Chart


Problem

When I go up / down in my Option Types DataGridView, it will paint the Mandatory and Additional sections depending on which Option Type I choose. After doing this for a while (70 or so times), I get the generic error in the GDI.

As you can see in the screenshot above, one of the additional edit buttons are not displayed correctly (this is where the error occurs). It is always on the following line:

ico = Icon.FromHandle(bmpFind.GetHicon)

See complete code below:

Code

Private Sub dgvAdditionalOptions_CellPainting(sender As Object, e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles dgvAdditionalOptions.CellPainting
    'Dim bmpFind As Bitmap
    Dim drRow As HunterManagement.dtConveyorFunctionAdditionalOptionsRow
    Dim myOptn As clsOptions

    If dgvAdditionalOptions.Columns(e.ColumnIndex).Name = "ColBtnEditAdditional" AndAlso e.RowIndex >= 0 Then
        drRow = dsHunterManagement.dtConveyorFunctionAdditionalOptions.FindByPK_ConveyorFunctionAdditionalOption(dgvAdditionalOptions.Rows(e.RowIndex).Cells("PK_ConveyorFunctionAdditionalOption").Value)
        myOptn = New clsOptions(CInt(drRow.FK_Option))
        e.Paint(e.CellBounds, DataGridViewPaintParts.All)

        If Not drRow Is Nothing AndAlso myOptn.InDrawing Then
            Using bmpFind As Bitmap = My.Resources.Edit_16x16_2 'Use 16x16 PNG / BitMap images
                Using ico As Icon = Icon.FromHandle(bmpFind.GetHicon)
                    e.Graphics.DrawIcon(ico, e.CellBounds.Left + 3, e.CellBounds.Top + 2.5)
                    e.Handled = True
                End Using
            End Using
        Else
            Using bmpFind As Bitmap = My.Resources.Edit_Disabled_16x16_2 'Use 16x16 PNG / BitMap images
                Using ico As Icon = Icon.FromHandle(bmpFind.GetHicon)
                    e.Graphics.DrawIcon(ico, e.CellBounds.Left + 3, e.CellBounds.Top + 2.5)
                    e.Handled = True
                End Using
            End Using
        End If
    ElseIf dgvAdditionalOptions.Columns(e.ColumnIndex).Name = "ColBtnDeleteAdditional" AndAlso e.RowIndex >= 0 Then
        e.Paint(e.CellBounds, DataGridViewPaintParts.All)
        Using bmpFind As Bitmap = My.Resources.Delete_16x16 'Use 16x16 PNG / BitMap images
            Using ico As Icon = Icon.FromHandle(bmpFind.GetHicon)
                e.Graphics.DrawIcon(ico, e.CellBounds.Left + 2, e.CellBounds.Top + 2.5)
                e.Handled = True
            End Using
        End Using
    End If
End Sub

I tried searching this problem and it is all related to 'saving' an image... I am not saving an image though, I am only getting the icon of a BMP image. I must be forgetting to dispose something.

Any ideas?

Alex
  • 4,821
  • 16
  • 65
  • 106
  • you are using a bitmap and icon object to display an image which seems excessive. if that column is a `DataGridViewImageColumn`, you can just use an image and be done with it. – Ňɏssa Pøngjǣrdenlarp Aug 28 '14 at 20:21
  • @Plutonix I'm using `DataGridViewButtonColumn` and trying to keep them in a 16x16 size format. I even tweaked it to use a `DataGridViewDisableButtonColumn` – Alex Aug 29 '14 at 12:15

1 Answers1

1

Typically this error is caused my a gdi+ leak. You need to Dispose the Icon which is a gdi+ resource. Add ico.Dispose once you're done with it.

When using Icon.FromHandle, you need to manually clean it up via DestroyIcon API.

When using this method you must dispose of the resulting icon using the DestroyIcon method in the Win32 API to ensure the resources are released.

Refer this answer, Hans gives a workaround for this problem.

Also note that you must Dispose the Bitmap also when you get it from Resources.YourBitmap because Resources.YourBitmap basically creates a new bitmap everytime it is called. Bitmap is also a gdi+ resource, you ought to dispose that also.

As @Hanspassant noted in comments prefer Using statements to Dispose the resources. They provide a convenient and reliable way of disposing a resource.

Community
  • 1
  • 1
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • I tried that right after the e.Graphics.DrawIcon() and it still does it. Am I not placing it at the correct place? – Alex Aug 28 '14 at 20:12
  • Updated my answer, You need to call `DestroyIcon` api. I'd suggest you to store the `Icon` as instance field and no need to create new again and again. That's also another work around. – Sriram Sakthivel Aug 28 '14 at 20:23
  • +1 for the help. I'll try it out tomorrow when I get back to work. If it works I'll accept your answer. Thank you for the help again – Alex Aug 28 '14 at 20:24
  • You need to point out that the bitmaps need to be disposed as well. Doesn't matter that they are resources. And recommend the Using statement. – Hans Passant Aug 28 '14 at 20:30
  • @HansPassant It was there in original question, If you see edit history you'll come to know. That's the reason I haven't pointed out. I'll add that also. Thanks. – Sriram Sakthivel Aug 28 '14 at 20:34
  • Yeah I removed the BMP Dispose because it was a test I was doing. I'll try this out – Alex Aug 29 '14 at 12:09
  • @SriramSakthivel I will have to try out Hans' GDI hack. After placing the code in using statements, I still get the error. I will update my post with my current code – Alex Aug 29 '14 at 12:19
  • Yes, try hans's hack and don't forget to use the `Using` statements. – Sriram Sakthivel Aug 29 '14 at 12:21
  • @SriramSakthivel Thank you for the help, I used the DestroyIcon API first. Using this link: http://msdn.microsoft.com/en-us/library/vstudio/system.drawing.icon.fromhandle(v=vs.90).aspx This solved the issue, the OBjects GDI process does not go higher than 500 now. – Alex Aug 29 '14 at 12:28